Existe un «canónica» forma de hacer eso? He estado usando head -n | tail -1 que hace el truco, pero me he estado preguntando si hay una fiesta herramienta que específicamente extractos de una línea (o un rango de líneas) de un archivo.

Por «canónica» me refiero a un programa cuya principal función es hacer que.

  • El «Unix» es la cadena de herramientas que hagan su trabajo respectivo bien. Así que yo creo que ya ha encontrado un método muy conveniente. Otros métodos incluyen awk y sed y estoy seguro de que alguien puede venir para arriba con un Perl de una línea o así 😉
  • El doble comando sugiere que la head | tail solución sub-óptima. Otros más cerca de la solución óptima se han sugerido.
  • Han ejecutó puntos de referencia sobre la solución que es la forma más rápida para un caso promedio?
  • Puntos de referencia (para un rango) en el gato de la línea X línea Y en un enorme archivo en Unix & Linux. (cc @Marcin, en caso de que usted todavía se pregunta, después de dos años)
  • El head | tail solución no funciona, si se consulta una línea que no existe en la entrada: se va a imprimir la última línea.

18 Comentarios

  1. 691

    head y de la tubería con tail será lenta para un archivo enorme. Yo sugeriría sed como este:

    sed 'NUMq;d' file

    Donde NUM es el número de la línea que desea imprimir; así, por ejemplo, sed '10q;d' file para imprimir la línea 10 de file.

    Explicación:

    NUMq dejar de fumar de inmediato cuando el número de línea es NUM.

    d va a eliminar de la línea en lugar de la impresión; este es inhibida en la última línea, porque el q hace que el resto de la secuencia de comandos que se va a saltar al dejar de fumar.

    Si usted tiene NUM en una variable, usted querrá usar comillas dobles en lugar de una sola:

    sed "${NUM}q;d" file
    • Para los que preguntan, esta solución parece ser aproximadamente de 6 a 9 veces más rápido que el sed -n 'NUMp' y sed 'NUM!d' soluciones que se proponen a continuación.
    • Creo que tail -n+NUM file | head -n1 es probable que sea igual de rápido o más rápido. Al menos, era (mucho) más rápido en mi sistema cuando lo he probado con NUM ser 250000 en un archivo con la mitad de un millón de líneas. YMMV, pero yo no veo por qué sería.
    • Tienes razón, parece que tail|head es de aproximadamente 2 a 3 veces más rápido que el sed comando propuesto en esta respuesta — yo lo he probado así…
    • He creado un archivo con 100 millones de líneas en /dev/shm. Ambos sed 'NUM!d' y sed -n NUMp necesita 14.8 segundos en tiempo real para obtener el 100 millonésimas de línea. Pero sed 'NUMq;d' toma 15.1 segundos. Y tail|head sólo tomó 3.0 segundos en tiempo real!
    • Poner un número en la aceleración no tiene mucho sentido, debido a que la aceleración depende enteramente de «¿qué tan lejos hacia abajo» en el archivo de la línea de meta, dado que esta respuesta de la optimización se encuentra en salir de inmediato después de la impresión de la línea de destino, y así no tener que leer el resto de del archivo.
    • Yo veo lo mismo en Ubuntu 12.04, donde el tail/head-based solution is about 5 times faster, but, curiously, on OS X 10.9.3 the roles are reversed: the sed` solución es más rápida, aunque no por mucho. Igualmente curiosamente, ambas soluciones corrió mucho más lentamente en OSX que en Ubuntu.
    • Al elegir el look para el el último de la línea en su prueba de negar esta respuesta es específica de optimización: salir de inmediato después de la impresión de la línea de meta – inténtelo de nuevo con una línea en el medio. Además, la diferencia entre 14.8 y 15.1 segundos simplemente podría explicarse con la variable tiempo de ejecución condiciones (lo ocupado que su equipo pasó a ser cuando las pruebas ran) – en su caso de prueba de 3 sed soluciones son prácticamente idénticas, después de todo.
    • Supongo que tiene que ver con la aplicación de tail, e indirectamente con el stdio. Usted puede tratar de comparar tail -n+$HUGE foo con el UUOC versión: cat foo | tail -n+$HUGE. A veces que en realidad acelera las cosas (a pesar de todas las bromas acerca de UUOC), ya que las derrotas no optimizaciones como mmap.
    • de los comentarios anteriores) En Linux (Ubuntu 12.04, Fedora 20), utilizando cat es de hecho rápido (casi dos veces más rápido), pero sólo si el archivo no se ha almacenado en caché aún. una Vez que el archivo se almacena en caché, el uso directo de el argumento de nombre de archivo es más rápido (aproximadamente 1/3 más rápido), mientras que cat rendimiento se mantiene el mismo. Curiosamente, en OS X 10.9.3 nada de esto parece hacer ninguna diferencia: cat / no cat, archivo de la caché o no. @anubhava: el placer es mío.
    • no estoy seguro de entender tu comentario acerca de poner un número de la aceleración no hacer mucho sentido, ya que es lo que estamos haciendo en los siguientes comentarios ? De todos modos, por supuesto, la aceleración depende del caso de prueba, en la instalación, e incluso más. Pero se me figura que dar una buena idea de cuál es la diferencia puede ser.
    • Mis números se refieren a un específico del caso de prueba (es decir, @rici, y aún los resultados son solo para darle un sentido general, como hay muchas otras variables). Que estaba tratando de hacer un general declaración acerca de la aceleración, que es inútil, que por las razones expuestas. Para decirlo de otra manera: sus números son de sentido, a menos que se describa la prueba específica escenario. E. g.: Con el mismo 500,000 línea del archivo de entrada (generado con seq 500000 > file), si pongo la PRIMERA línea, yo más o menos ver el speedup de describir; si tengo la ÚLTIMA línea, NO hay aceleración.
    • lo siento por no haber declarado lo que es obvio. Los resultados no dependen sólo del tamaño del archivo y el número de la línea que se está tratando de extraer, sino también en su configuración de hardware (por ejemplo, mis pruebas fueron realizadas en un SSD, supongo que no hace la diferencia), y de que los recursos ya están en usa en el momento en que se realiza la prueba. Por lo que vale, no le un número, pero rangos de, precisamente porque he probado diferentes casos de prueba—, evitando los múltiples casos como el de la primera/última de las líneas.
    • Dada la naturaleza específica de esta optimización, incluso su rangos de de los números se no como una declaración general. La única general para llevar es este: (a) esta optimización puede ser aplicada a todos los de entrada, (b) el efectos van desde ninguno a la dramática, según el índice de la línea de buscarse en relación con el número de total de líneas.
    • En la mayoría de los test que hice, cola|cabeza funcionado mejor. Incluso mejor que el de la cabeza|cola para los casos cerca del principio del archivo, el final del archivo o en el medio. Lea todos los detalles, y realizar sus propias pruebas usando el script que he publicado aquí: http://unix.stackexchange.com/a/216614/79743.
    • Limpio pruebas, pero usted no es de mencionar que usted está aplicando una optimización: elegir si aplicar tail o head en primer lugar, dependiendo de la cantidad de la línea buscada relación al total de número de línea, que se requiere contar las líneas de entrada de seguridad delantero. Por lo tanto, usted necesita 2 comandos independientes y también se necesita un factor de recuento de las líneas en los tiempos. También tenga en cuenta que si su entrada viene desde stdin o un FIFO, contando hasta el frente puede incluso no ser una opción (porque la entrada es consumida la primera vez que se lee).
    • También: sistemas de archivos y la utilidad de las implementaciones a través de diferentes plataformas, y aunque no nos factor en el tiempo que se necesita para contar las líneas, en mi OSX 10.10.4 de la máquina, sed todavía – notablemente – supera a su optimizado head / tail solución en todos los casos de prueba, pero la última: el número de línea al final de un archivo muy grande. En general, cuanto más cerca de la línea de meta es el final del archivo, y el más grande es el archivo de entrada, la mejor la optimización de su trabajo. Su dirección URL como un enlace (se omite el código de formato): unix.stackexchange.com/a/216614/79743
    • Podrías explicar, por favor, este comando? Sed líneas de proceso hasta que se cumpla el número de línea NUM, a continuación, ejecuta q, por ejemplo, se detiene. Luego d se ejecuta y por qué elimina todas las líneas de antes?No todas las líneas de 0 a NUM es en memoria a este paso, a continuación, sed elimina y la corriente de salida de línea o …?
    • sed 'NUMq de salida será de primera NUM archivos y ;d eliminará todos, pero la última línea.
    • Este parece interactuar curiosamente con un tubo de xargs — me sale un error que dice que xargs ha sido denunciado por signal 13.
    • Lo he probado y ha funcionado con xargs bien.
    • su solución es más fácil de recordar y fácil de modificar para obtener más líneas que sólo la Enésima. Si la publica como una solución me gustaría upvote.
    • Cuando las pruebas de rendimiento de las operaciones, asegúrese de descartar el sistema de e/S de caché como un factor. La segunda vez que un archivo es leído, es más probable que se leen de la memoria RAM, mientras que el primer tiempo fue de disco, que puede ser una razón por la que la segunda operación es mucho más rápido. Asegurarse de que hay suficiente memoria libre para cach todo el archivo y leerlo con ‘cat archivo >/dev/null’ a la memoria caché antes de ejecutar los puntos de referencia, o desactive el sistema de e/S de caché entre ellos en su lugar.
    • que las salidas de mí todo el archivo. el consejo no funciona.
    • Esta solución sólo es rápido si usted tiene una enorme e/S de velocidad. Estoy leyendo desde una memoria EEPROM y esto es al menos 3 veces más lento como una solución. (cola+cabeza de la solución es más lento de lo que quiero decir)
    • podría ser, pero probablemente hay un gran número de otras diferencias en su sistema que necesitan ser considerados. No tomar en caché en cuenta, como se ha mencionado un par de comentarios arriba del tuyo.

  2. 263
    sed -n '2p' < file.txt

    imprimirá 2ª línea de

    sed -n '2011p' < file.txt

    2011th línea

    sed -n '10,33p' < file.txt

    de la línea 10 a la línea 33

    sed -n '1p;3p' < file.txt

    1ª y 3ª línea de

    y así sucesivamente…

    Para agregar líneas con sed, usted puede comprobar esto:

    sed: inserta una línea en una posición determinada

    • ¿Por qué es el ‘<‘ necesario en este caso? No puedo lograr el mismo resultado sin ella?
    • el < en este caso, no es necesario. Simplemente, es mi preferencia usando redirecciones, porque me utiliza a menudo redirecciones como sed -n '100p' < <(some_command) – así, universal sintaxis :). NO es menos eficaz, ya que la redirección se realiza con la carcasa cuando se bifurcan en sí, por lo que… es sólo una preferencia… (y sí, es un personaje más) 🙂
    • En realidad es de 2 caracteres más ya que normalmente se pone el ‘<‘ así como un espacio extra » después de < como oppposed a un solo espacio si no hubiera utilizado el < 🙂
    • el espacio es un personaje demasiado? 🙂 /bueno, sólo es una broma – youre derecho/ 🙂
    • Esto es alrededor de 5 veces más lento que el de la cola / cabeza combinación cuando la lectura de un archivo con 50M filas
    • por supuesto, si alguien necesita hacer optimizaciones. Pero en mi humilde opinión para el «común» de los problemas es aceptar y la diferencia es imperceptible. También, el head/tail no resuelve el sed -n '1p;3p' escenario – aka impresión más filas no adyacentes…
    • Amén! Sólo quería crear una nota para los tontos como yo que tienen que hacer la línea de las búsquedas de miles de millones de veces para alguna tarea…
    • por supuesto, la nota es correcta y necesaria. 🙂

  3. 82

    Tengo una situación única, en donde puedo referencia a las soluciones propuestas en esta página, y así que estoy escribiendo esta respuesta como una consolidación de las soluciones propuestas con los tiempos de ejecución para cada uno.

    Configurar

    Tengo un 3.261 gigabyte de texto ASCII archivo de datos con un par clave-valor para cada fila. El archivo contiene 3,339,550,320 filas en total y desafía a la apertura en cualquier editor que he probado, incluyendo mi go-to de Vim. Necesito un subconjunto de este archivo con el fin de investigar algunos de los valores que he descubierto sólo empieza alrededor de la fila ~500,000,000.

    Porque el archivo tiene tantas filas:

    • Necesito para extraer sólo un subconjunto de las filas para hacer algo útil con los datos.
    • La lectura a través de cada fila que conduce a los valores que me importa es que va a tomar mucho tiempo.
    • Si la solución se lee más allá de las filas de los que me importan y continúa leyendo el resto del archivo que será un desperdicio de tiempo a la lectura de casi 3 mil millones de irrelevante filas y tomar 6x más de lo necesario.

    Mi mejor de los casos, es una solución que se extrae sólo una sola línea desde el archivo sin la lectura de cualquiera de las otras filas en el archivo, pero no puedo pensar en cómo iba a hacerlo en Bash.

    Para los fines de mi cordura no voy a estar tratando de leer el 500,000,000 líneas que necesitaría para mi propio problema. En su lugar voy a estar tratando de extraer de la fila de 50,000,000 de 3,339,550,320 (que significa leer el archivo completo se llevará a 60 veces más de lo necesario).

    Me va a utilizar el time integrado en la referencia de cada comando.

    Línea de base

    Primero vamos a ver cómo la head tail solución:

    $ time head -50000000 myfile.ascii | tail -1
    pgm_icnt = 0
    
    real    1m15.321s

    De la línea de base para la fila 50 millones de 00:01:15.321, si yo hubiera ido en la línea de 500 millones que probablemente estaría ~12.5 minutos.

    corte

    Estoy dudosa de esto, pero es bien vale la pena un tiro:

    $ time cut -f50000000 -d$'\n' myfile.ascii
    pgm_icnt = 0
    
    real    5m12.156s

    Este tuvo 00:05:12.156 a ejecutar, que es mucho más lento que la línea de base! No estoy seguro si es a través de leer el archivo completo o solo hasta la línea de 50 millones antes de detenerse, pero sin importar esto no parece una solución viable para el problema.

    AWK

    Sólo corrí la solución con el exit porque yo no iba a esperar que el archivo a ejecutar:

    $ time awk 'NR == 50000000 {print; exit}' myfile.ascii
    pgm_icnt = 0
    
    real    1m16.583s

    Este código se ejecutaba en 00:01:16.583, que es sólo ~1 segundo más lento, pero todavía no una mejora en la línea de base. A este ritmo, si la salida del comando habían sido excluidas de que probablemente habría tomado alrededor de ~76 minutos para leer el archivo completo!

    Perl

    Me encontré con la existente en Perl solución:

    $ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
    pgm_icnt = 0
    
    real    1m13.146s

    Este código se ejecutaba en 00:01:13.146, que es de ~2 segundos más rápido que la línea de base. Si me gustaría ejecutar en el pleno 500,000,000 probablemente llevaría a ~12 minutos.

    sed

    La respuesta en la junta, aquí está mi resultado:

    $ time sed "50000000q;d" myfile.ascii
    pgm_icnt = 0
    
    real    1m12.705s

    Este código se ejecutaba en 00:01:12.705, que es de 3 segundos más rápido que la línea de base, y ~0,4 segundos más rápido que el Perl. Si me gustaría ejecutar en el pleno 500,000,000 filas que probablemente habría tomado ~12 minutos.

    mapfile

    He bash 3.1 y por tanto no puede probar el mapfile solución.

    Conclusión

    Parece que, para la mayor parte, es difícil de mejorar el head tail solución. En el mejor de los sed solución proporciona un ~3% de incremento en eficiencia.

    (porcentajes calculados con la fórmula % = (runtime/baseline - 1) * 100)

    Fila 50,000,000

    1. 00:01:12.705 (-00:00:02.616 = -3.47%) sed
    2. 00:01:13.146 (-00:00:02.175 = -2.89%) perl
    3. 00:01:15.321 (+00:00:00.000 = +0.00%) head|tail
    4. 00:01:16.583 (+00:00:01.262 = +1.68%) awk
    5. 00:05:12.156 (+00:03:56.835 = +314.43%) cut

    Fila 500,000,000

    1. 00:12:07.050 (-00:00:26.160) sed
    2. 00:12:11.460 (-00:00:21.750) perl
    3. 00:12:33.210 (+00:00:00.000) head|tail
    4. 00:12:45.830 (+00:00:12.620) awk
    5. 00:52:01.560 (+00:40:31.650) cut

    Fila 3,338,559,320

    1. 01:20:54.599 (-00:03:05.327) sed
    2. 01:21:24.045 (-00:02:25.227) perl
    3. 01:23:49.273 (+00:00:00.000) head|tail
    4. 01:25:13.548 (+00:02:35.735) awk
    5. 05:47:23.026 (+04:24:26.246) cut
    • Me pregunto cuánto tiempo solo gato’ting todo el archivo en /dev/null tomaría. (¿Y si esto era sólo un disco duro de referencia?)
  4. 46

    Con awk es bastante rápido:

    awk 'NR == num_line' file

    Cuando esto es así, el comportamiento por defecto de awk se realiza: {print $0}.


    Versiones alternativas

    Si el archivo pasa a ser enorme, es mejor que exit después de la lectura de la línea requerida. De esta manera te ahorras el tiempo de la CPU.

    awk 'NR == num_line {print; exit}' file

    Si quieres dar el número de línea de un bash variable que puede utilizar:

    awk 'NR == n' n=$num file
    awk -v n=$num 'NR == n' file   # equivalent
    • Tenía la esperanza de leer un awk responder aquí. Buena nota en la salida, ¿no han pensado en ello. Quizás también incluyen el equivalente awk -v n=$num 'NR == n'?
    • gracias, acabo de actualizar a esta versión equivalente!
    • awk == legible por humanos sed
  5. 26

    Wow, todas las posibilidades!

    Intente esto:

    sed -n "${lineNum}p" $file

    o uno de estos, dependiendo de su versión de Awk:

    awk  -vlineNum=$lineNum 'NR == lineNum {print $0}' $file
    awk -v lineNum=4 '{if (NR == lineNum) {print $0}}' $file
    awk '{if (NR == lineNum) {print $0}}' lineNum=$lineNum $file

    (Puede intentar la nawk o gawk comando).

    Hay una herramienta que sólo hace la impresión de una línea particular? No es una de las herramientas estándar. Sin embargo, sed es probablemente el más cercano y simple de usar.

  6. 20

    Esta pregunta está etiquetado Bash, aquí está el Bash (≥4) modo de hacer: utilizar mapfile con el -s (salto) y -n (recuento) de la opción.

    Si usted necesita para obtener la 42ª línea de un archivo file:

    mapfile -s 41 -n 1 ary < file

    En este punto, usted tendrá una matriz ary los campos que contienen las líneas de file (incluyendo la final de salto de línea), donde se han omitido los primeros 41 líneas (-s 41), y se detuvo después de la lectura de una línea (-n 1). Así que es realmente la línea 42. Imprimir:

    printf '%s' "${ary[0]}"

    Si usted necesita un rango de líneas, decir que el rango de 42-666 (inclusive), y a decir que usted no quiere hacer las matemáticas sí mismo, y las imprime en la salida estándar (stdout):

    mapfile -s $((42-1)) -n $((666-42+1)) ary < file
    printf '%s' "${ary[@]}"

    Si usted necesita para procesar estas líneas demasiado, realmente no es conveniente para almacenar la final de salto de línea. En este caso, utilice la -t opción (trim):

    mapfile -t -s $((42-1)) -n $((666-42+1)) ary < file
    # do stuff
    printf '%s\n' "${ary[@]}"

    Usted puede tener una función que lo haga:

    print_file_range() {
        # $1-$2 is the range of file $3 to be printed to stdout
        local ary
        mapfile -s $(($1-1)) -n $(($2-$1+1)) ary < "$3"
        printf '%s' "${ary[@]}"
    }

    No hay comandos externos, sólo Bash builtins!

  7. 15

    Según mis pruebas, en términos de rendimiento y mejorar la legibilidad mi recomendación es:

    tail -n+N | head -1

    N es el número de línea que desee. Por ejemplo, tail -n+7 input.txt | head -1 imprimirá la línea 7 del archivo.

    tail -n+N va a imprimir todo a partir de la línea de N, y head -1 hará parada después de una línea.


    La alternativa head -N | tail -1 es quizás un poco más legible. Por ejemplo, esto imprimirá la línea 7:

    head -7 input.txt | tail -1

    Cuando se trata de rendimiento, no hay mucha diferencia para los tamaños más pequeños, pero va a ser superado por el tail | head (desde arriba) cuando los archivos se conviertan en grandes.

    La parte superior de votación de los sed 'NUMq;d' es interesante saber, pero yo diría que va a ser entendido por un menor número de personas fuera de la caja de la cabeza/cola de solución y también es más lento que el de la cola con la cabeza.

    En mis pruebas, los dos colas/jefes versiones superó sed 'NUMq;d' constantemente. Lo que está en consonancia con los demás puntos de referencia que fueron publicados. Es difícil encontrar un caso en el que las colas/jefes era realmente malo. Tampoco es sorprendente, ya que estas son las operaciones que se puede esperar a ser muy optimizado en un moderno sistema Unix.

    Para tener una idea acerca de las diferencias de rendimiento, estas son las que tengo un gran archivo (9.3 G):

    • tail -n+N | head -1: 3,7 seg
    • head -N | tail -1: 4.6 sec
    • sed Nq;d: 18.8 sec

    Resultados pueden diferir, pero el rendimiento head | tail y tail | head es, en general, comparable a los más pequeños de insumos, y sed es siempre más lento por un factor significativo (alrededor de 5 veces o así).

    Para reproducir mi punto de referencia, usted puede tratar el siguiente, pero se advirtió que se va a crear un 9,3 G archivo en el directorio de trabajo actual:

    #!/bin/bash
    readonly file=tmp-input.txt
    readonly size=1000000000
    readonly pos=500000000
    readonly retries=3
    
    seq 1 $size > $file
    echo "*** head -N | tail -1 ***"
    for i in $(seq 1 $retries) ; do
        time head "-$pos" $file | tail -1
    done
    echo "-------------------------"
    echo
    echo "*** tail -n+N | head -1 ***"
    echo
    
    seq 1 $size > $file
    ls -alhg $file
    for i in $(seq 1 $retries) ; do
        time tail -n+$pos $file | head -1
    done
    echo "-------------------------"
    echo
    echo "*** sed Nq;d ***"
    echo
    
    seq 1 $size > $file
    ls -alhg $file
    for i in $(seq 1 $retries) ; do
        time sed $pos'q;d' $file
    done
    /bin/rm $file

    Aquí está la salida de una carrera en mi máquina (ThinkPad X1 de Carbono con un SSD y 16G de memoria). Asumo que para el final de la carrera todo lo que vendrá a partir de la memoria caché, y no desde el disco:

    *** head -N | tail -1 ***
    500000000
    
    real    0m9,800s
    user    0m7,328s
    sys     0m4,081s
    500000000
    
    real    0m4,231s
    user    0m5,415s
    sys     0m2,789s
    500000000
    
    real    0m4,636s
    user    0m5,935s
    sys     0m2,684s
    -------------------------
    
    *** tail -n+N | head -1 ***
    
    -rw-r--r-- 1 phil 9,3G Jan 19 19:49 tmp-input.txt
    500000000
    
    real    0m6,452s
    user    0m3,367s
    sys     0m1,498s
    500000000
    
    real    0m3,890s
    user    0m2,921s
    sys     0m0,952s
    500000000
    
    real    0m3,763s
    user    0m3,004s
    sys     0m0,760s
    -------------------------
    
    *** sed Nq;d ***
    
    -rw-r--r-- 1 phil 9,3G Jan 19 19:50 tmp-input.txt
    500000000
    
    real    0m23,675s
    user    0m21,557s
    sys     0m1,523s
    500000000
    
    real    0m20,328s
    user    0m18,971s
    sys     0m1,308s
    500000000
    
    real    0m19,835s
    user    0m18,830s
    sys     0m1,004s
    • Es el rendimiento diferentes entre head | tail vs tail | head? O no depende de la línea que está siendo impreso (principio del archivo vs final del archivo)?
    • No tengo cifras concretas, pero una desventaja de primer uso de la cola seguido por una «cabeza -1» es que usted necesita para saber la longitud total por adelantado. Si usted no sabe, usted tendría que contar en primer lugar, que será una pérdida en cuanto al rendimiento. Otra desventaja es que es menos intuitivo de usar. Por ejemplo, si usted tiene el número 1 a 10 y desea obtener la línea 3, usted tendría que usar «cola -8 | head -1». Que es más propenso al error de «cabeza -3 | tail -1».
    • lo siento, debería haber incluido un ejemplo evidente. head -5 | tail -1 vs tail -n+5 | head -1. De hecho, he encontrado otra respuesta que hizo una prueba de comparación y se encontró tail | head a ser más rápido. stackoverflow.com/a/48189289
    • Gracias por mencionarlo! Hice algunas pruebas y tienen que estar de acuerdo que siempre fue un poco más rápido, independiente de la posición de la línea de lo que yo vi. Dado que, he cambiado mi respuesta y también se incluye el punto de referencia en caso de que alguien quiera reproducir.
  8. 11

    También puede utilizarse sed de impresión y cierre:

    sed -n '10{p;q;}' file   # print line 10
    • ¿Qué es -n haciendo ?
    • El -n opción deshabilita la acción predeterminada para imprimir cada línea, como seguramente habría encontrado por un rápido vistazo a la página man.
    • En GNU sed todos los sed respuestas son la misma velocidad. Por lo tanto (para GNU sed) esta es la mejor sed respuesta, ya que sería un ahorro de tiempo para los archivos grandes y pequeñas línea n de los valores.
  9. 6

    La más rápida solución para archivos de gran tamaño es siempre la cola|cabeza, a condición de que las dos distancias:

    • desde el inicio del archivo en la línea de partida. Vamos a llamarlo S
    • la distancia desde la última línea al final del archivo. Sea E

    son conocidos. Entonces, podemos usar este:

    mycount="$E"; (( E > S )) && mycount="+$S"
    howmany="$(( endline - startline + 1 ))"
    tail -n "$mycount"| head -n "$howmany"

    howmany es sólo el número de líneas requeridas.

    Algo más de detalle en https://unix.stackexchange.com/a/216614/79743

    • Por favor aclarar las unidades de S y E, (es decir, bytes, caracteres o líneas).
  10. 4

    Todas las respuestas anteriores responder directamente a la pregunta. Pero he aquí una manera menos directa la solución, pero potencialmente más importante la idea, para provocar el pensamiento.

    Desde longitudes de línea arbitraria, todos los bytes del archivo antes de la línea n necesidad para ser leído. Si usted tiene un archivo grande o la necesidad de repetir esta tarea muchas veces, y este proceso lleva mucho tiempo, entonces usted debe pensar seriamente acerca de si se debe almacenar los datos en una forma diferente en el primer lugar.

    La verdadera solución es tener un índice, por ejemplo, en el inicio del archivo, indicando las posiciones donde las líneas de comenzar. Usted podría utilizar un formato de base de datos, o simplemente añadir una tabla en el inicio del archivo. Alternativamente crear un archivo de índice para acompañar a su gran archivo de texto.

    por ejemplo, usted podría crear una lista de posiciones de carácter de salto de línea:

    awk 'BEGIN{c=0;print(c)}{c+=length()+1;print(c+1)}' file.txt > file.idx

    a continuación, leer con tail, que en realidad seeks directamente en el punto apropiado en el archivo!

    por ejemplo, para obtener la línea de 1000:

    tail -c +$(awk 'NR=1000' file.idx) file.txt | head -1
    • Esto puede no funcionar con 2 bytes /caracteres multibyte, ya que awk es de carácter «consciente», pero la cola no es.
    • Yo no he probado este en contra de un archivo de gran tamaño.
    • Ver también esta respuesta.
    • Alternativamente – dividir el archivo en archivos más pequeños!
  11. 4

    Como una continuación de CaffeineConnoisseur muy útil benchmarking respuesta… yo estaba curioso en cuanto a cómo de rápido el ‘mapfile’ método se comparó con los otros (como que no se ha probado), así que he intentado una rápida y sucia comparación de velocidad yo como tengo bash 4 a la mano. La tiró en una prueba de la «cola» | head» método (en lugar de la cabeza | cola) que se menciona en uno de los comentarios en la respuesta mientras yo estaba en él, a medida que las personas están cantando sus alabanzas. Yo no tengo nada, casi del tamaño de la prueba utilizada; el mejor que pude encontrar en el aviso corto fue un 14M pedigree archivo (líneas largas que son espacios separados, justo debajo de 12000 líneas).

    Versión corta: mapfile parece más rápido que el método del corte, pero más lento que todo lo demás, por lo que yo llamaría un fiasco. cola | de la cabeza, OTOH, parece que podría ser el más rápido, aunque con un archivo de este tamaño la diferencia no es considerable en comparación con sed.

    $ time head -11000 [filename] | tail -1
    [output redacted]
    
    real    0m0.117s
    
    $ time cut -f11000 -d$'\n' [filename]
    [output redacted]
    
    real    0m1.081s
    
    $ time awk 'NR == 11000 {print; exit}' [filename]
    [output redacted]
    
    real    0m0.058s
    
    $ time perl -wnl -e '$.== 11000 && print && exit;' [filename]
    [output redacted]
    
    real    0m0.085s
    
    $ time sed "11000q;d" [filename]
    [output redacted]
    
    real    0m0.031s
    
    $ time (mapfile -s 11000 -n 1 ary < [filename]; echo ${ary[0]})
    [output redacted]
    
    real    0m0.309s
    
    $ time tail -n+11000 [filename] | head -n1
    [output redacted]
    
    real    0m0.028s

    Espero que esto ayude!

  12. 3

    Si tienes varias líneas delimitadas por \n (normalmente de nueva línea). Usted puede utilizar ‘cortar’ así:

    echo "$data" | cut -f2 -d$'\n'

    Obtendrá la 2ª línea del archivo. -f3 le da la 3ª línea.

    • También se puede utilizar para mostrar varias líneas: cat FILE | cut -f2,5 -d$'\n' mostrará las líneas 2 y 5 del ARCHIVO. (Pero no mantiene el orden.)
  13. 2

    Un montón de buenas respuestas ya. A mi personalmente me van con awk. Para mayor comodidad, si usted usa bash, sólo tiene que añadir el siguiente a la ~/.bash_profile. Y, la próxima vez que inicie sesión en (o si su origen .bash_profile después de esta actualización), tendrá una nueva ingenioso «n» función disponible para canalizar sus archivos a través de.

    Ejecutar este o ponerlo en tu ~/.bash_profile (si se usa bash) y volver a abrir bash (o ejecutar source ~/.bach_profile)

    # print just the nth piped in line
    nth () { awk -vlnum=${1} 'NR==lnum {print; exit}'; }

    Entonces, para usarlo, simplemente canalizar a través de ella. E. g.,:

    $ yes line | cat -n | nth 5
    5 line

  14. 1

    Para imprimir línea n usando sed con una variable como número de línea:

    a=4
    sed -e $a'q:d' file

    Aquí en ‘-e’ bandera es para agregar secuencias de comandos para el comando a ser ejecutado.

    • El colon es un error de sintaxis, y debe ser un punto y coma.
  15. 1

    El uso de lo que los otros mencionados, quería que esta fuera una rápida & dandy función en mi shell bash.

    Crear un archivo: ~/.functions

    Añadir a esto el contenido:


    getline() {
    line=$1
    sed $line'q;d' $2
    }

    A continuación, agregue esto a su ~/.bash_profile:

    source ~/.functions

    Ahora cuando se abre un nuevo bash ventana, usted puede llamar a la función así:

    getline 441 myfile.txt

  16. 0

    He puesto algunas de las respuestas anteriores en un bash script que usted puede poner en un archivo llamado get.sh y enlace a /usr/local/bin/get (o cualquier otro nombre que prefiera).

    #!/bin/bash
    if [ "" == "" ]; then
        echo "error: blank line number";
        exit 1
    fi
    re='^[0-9]+$'
    if ! [[ $1 =~ $re ]] ; then
        echo "error: line number arg not a number";
        exit 1
    fi
    if [ "" == "" ]; then
        echo "error: blank file name";
        exit 1
    fi
    sed "q;d" $2;
    exit 0

    Asegurarse de que es ejecutable con

    $ chmod +x get

    Link para que esté disponible en el PATH con

    $ ln -s get.sh /usr/local/bin/get

    Disfrutar responsablemente!

    P

Dejar respuesta

Please enter your comment!
Please enter your name here