102 votos

¿Cómo mostrar ciertas líneas de un archivo de texto en Linux?

Supongo que todo el mundo conoce las útiles utilidades de la línea cmd de Linux head y tail . head permite imprimir las primeras X líneas de un archivo, tail hace lo mismo pero imprime el final del archivo. ¿Cuál es un buen comando para imprimir la mitad de un archivo? algo como middle --start 10000000 --count 20 (imprimir las líneas 10'000'000 hasta la 10'000'010).

Estoy buscando algo que trate con archivos grandes de manera eficiente. He probado tail -n 10000000 | head 10 y es horriblemente lento.

5 votos

posible duplicado de serverfault.com/questions/101900/

131voto

jason saldo Puntos 5036
sed -n '10000000,10000020p' filename

Podrías acelerarlo un poco así:

sed -n '10000000,10000020p; 10000021q' filename

En esos comandos, la opción -n causa sed para "suprimir la impresión automática del espacio del patrón". El p imprime el espacio del patrón actual" y el comando q El comando "Sale inmediatamente del sed script sin procesar ninguna otra entrada..." Las comillas son del sed man página .

Por cierto, su comando

tail -n 10000000 filename | head 10

comienza en la décima millonésima línea desde el fin del archivo, mientras que su comando "medio" parecería comenzar en la diezmillonésima parte del Inicio lo que equivaldría a:

head -n 10000010 filename | tail 10

El problema es que para los archivos no clasificados con líneas de longitud variable cualquier proceso va a tener que recorrer el archivo contando las nuevas líneas. No hay forma de atajar eso.

Sin embargo, si el archivo está ordenado (un archivo de registro con marcas de tiempo, por ejemplo) o tiene líneas de longitud fija, entonces puede buscar en el archivo basándose en una posición de bytes. En el ejemplo del archivo de registro, podría hacer una búsqueda binaria para un rango de tiempos como mi Python script aquí * lo hace. En el caso del archivo de longitud de registro fija, es realmente fácil. Sólo hay que buscar linelength * linecount caracteres en el archivo.

* Sigo queriendo publicar otra actualización de ese script</strkeep><strkeep>. Tal vez voy a llegar a ella uno de estos días.

0 votos

Aquí hay una sed versión de Charles middle función: middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; } . Manejará argumentos de archivos múltiples, nombres de archivos con espacios, etc. Los archivos múltiples se procesan juntos como si hubieran sido catados de la misma manera que sed normalmente lo hace (así que el medio 1000 100 archivo1 archivo2 abarcaría desde el final del primer archivo hasta el principio del segundo si el primero tiene menos de 1100 líneas).

0 votos

La función de mi comentario anterior se puede llamar con un parámetro de nombre de archivo: middle startline count filename o varios nombres de archivo: middle startline count file1 file2 file3 o con redirección: middle startline count < filename o en una tubería: some_command | recuento de la línea de salida media` o cat file* | middle startline count

0 votos

¿No debería la ` en tu comando sed ser una '? No consigo que funcione con el signo de retroceso pero funciona bien con la comilla simple.

32voto

Dox Puntos 161

Descubrí el siguiente uso de sed

sed -n '10000000,+20p'  filename

¡Espero que le sirva a alguien!

0 votos

Es bueno saber que hay una alternativa al argumento de la última línea propuesto por Dennis: un recuento de líneas como segundo sed -n que lo hace bastante legible.

0 votos

Un ejemplo de uso: extract_lines(){sed -n "$1,+$2p" <file>} que escribe en stdout.

5voto

Dennis Puntos 21

Es la primera vez que escribo aquí. De todos modos, esto es fácil. Digamos que quieres sacar la línea 8872 de tu archivo llamado file.txt. Así es como se hace:

cat -n archivo.txt | grep '^ *8872'

Ahora la cuestión es encontrar 20 líneas después de esto. Para lograrlo, hay que hacer lo siguiente

cat -n archivo.txt | grep -A 20 '^ *8872'

Para las líneas alrededor o antes de ver las banderas -B y -C en el manual de grep.

0 votos

Aunque eso es técnicamente correcto y una forma interesante de hacerlo en un archivo de tamaño razonable, tengo curiosidad por su eficacia cuando se trabaja con archivos del tamaño que pregunta el cartel.

0 votos

Varias líneas: cat -n archivo.txt | grep "^ \s\ +(10\|20\|30) \s\ +"

0 votos

cat -n file.txt | grep '^ *1' cede todas las líneas que tengan 1 en su lado derecho. ¿Cómo sacar la línea 1 con esta técnica? Sé que puedo encabezar -n 1....pero ¿cómo usar grep?

1voto

Charles Stewart Puntos 500

La respuesta de Dennis Sed es el camino a seguir. Pero usando sólo head & tail, bajo bash:

middle () { head -n $\[ $1 + $2 \] | tail -n $2; }

Esto escanea las primeras líneas de $1+$2 dos veces, por lo que es mucho peor que la respuesta de Dennis. Pero no es necesario recordar todas esas letras sed para usarlo....

0 votos

Utilizando $[...] está obsoleto, al menos en Bash. Además, te falta un parámetro de archivo.

0 votos

@Dennis: No falta ningún parámetro: se supone que debes usar esto en stdin, según middle 10 10 < /var/log/auth.log .

0voto

shardan Puntos 181

Una versión oneliner de color rubí.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Puede ser útil para alguien. Las soluciones con 'sed' proporcionadas por Dennis y Dox es muy agradable, incluso porque parece más rápido.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: