Herramienta Bash para obtener la enésima línea de un archivo

¿Existe una forma "canónica" de hacer eso? He estado usando head -n | tail -1 que hace el truco, pero me preguntaba si hay una herramienta Bash que extrae específicamente una línea (o un rango de líneas) de un archivo.

Por "canónico" me refiero a un programa cuya función principal es hacer eso.

preguntado el 16 de mayo de 11 a las 19:05

El "método Unix" es encadenar herramientas que hagan bien su trabajo respectivo. Así que creo que ya ha encontrado un método muy adecuado. Otros métodos incluyen awk y sed y estoy seguro de que a alguien se le puede ocurrir una frase de Perl o algo así;) -

El doble comando sugiere que el head | tail La solución es subóptima. Se han sugerido otras soluciones más cercanas a las óptimas. -

¿Ha realizado pruebas comparativas sobre qué solución es la más rápida para un caso medio? -

Puntos de referencia (para un rango) en cat línea X a línea Y en un archivo enorme on Unix y Linux. (cc @Marcin, en caso de que todavía se lo esté preguntando después de más de dos años) -

La head | tail La solución no funciona, si consulta una línea que no existe en la entrada: imprimirá la última línea. -

19 Respuestas

head y tubería con tail será lento para un archivo enorme. Yo sugeriría sed Me gusta esto:

sed 'NUMq;d' file

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

Explicación:

NUMq saldrá inmediatamente cuando el número de línea sea NUM.

d eliminará la línea en lugar de imprimirla; esto se inhibe en la última línea porque el q hace que se omita el resto del script al salir.

Si tienes NUM en una variable, querrá usar comillas dobles en lugar de simples:

sed "${NUM}q;d" file

Respondido 16 Feb 16, 07:02

Para aquellos que se preguntan, esta solución parece entre 6 y 9 veces más rápida que la sed -n 'NUMp' y sed 'NUM!d' soluciones propuestas a continuación. - Skippy le Grand Gourou

Creo que el tail -n+NUM file | head -n1 es probable que sea igual de rápido o más rápido. Al menos, fue (significativamente) más rápido en mi sistema cuando lo probé con NUM siendo 250000 en un archivo con medio millón de líneas. YMMV, pero realmente no veo por qué lo haría. - luminoso

no, no es. Sin q procesará el archivo completo - anubhava

@Fiddlestiques: No olvides citar para hacerlo foo="$(sed "4q;d" file4)" - anubhava

@anubhava - gracias - lo tengo ahora - echo "$ foo" en lugar de echo $ foo - Fiddlestiques

sed -n '2p' < file.txt

imprimirá la segunda línea

sed -n '2011p' < file.txt

Quinta línea

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

línea 10 hasta línea 33

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

1ª y 3ª línea

y así...

Para agregar líneas con sed, puede verificar esto:

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

contestado el 23 de mayo de 17 a las 13:05

¿Por qué es necesario el '<' en este caso? ¿No lograría el mismo resultado sin él? - Rafael Barbosa

@RafaelBarbosa el < en este caso no es necesario. Simplemente, prefiero usar redireccionamientos, porque a menudo utilizo redireccionamientos como sed -n '100p' < <(some_command) - entonces, sintaxis universal :). NO es menos efectivo, porque la redirección se realiza con shell cuando se bifurca, así que ... es solo una preferencia ... (y sí, es un carácter más) :) - jm666

@ jm666 En realidad, son 2 caracteres más ya que normalmente pondría el '<' así como un espacio extra '' después de <en oposición a un solo espacio si no hubiera usado el <:) rasen58

@ rasen58 ¿el espacio también es un personaje? :) / Está bien, es broma - tienes razón / :) - jm666

Esto es aproximadamente 5 veces más lento que la combinación de cola / cabeza cuando se lee un archivo con 50 millones de filas. duhaime

Tengo una situación única en la que puedo comparar las soluciones propuestas en esta página, por lo que escribo esta respuesta como una consolidación de las soluciones propuestas con tiempos de ejecución incluidos para cada una.

establecer

Tengo un archivo de datos de texto ASCII de 3.261 gigabytes con un par clave-valor por fila. El archivo contiene 3,339,550,320 filas en total y desafía la apertura en cualquier editor que haya probado, incluido mi Vim. Necesito crear un subconjunto de este archivo para investigar algunos de los valores que descubrí que solo comienzan alrededor de la fila ~ 500,000,000.

Porque el archivo tiene tantas filas:

  • Necesito extraer solo un subconjunto de las filas para hacer algo útil con los datos.
  • Leer todas las filas que conducen a los valores que me importan va a llevar mucho tiempo.
  • Si la solución lee más allá de las filas que me interesan y continúa leyendo el resto del archivo, perderá tiempo leyendo casi 3 mil millones de filas irrelevantes y tomará 6 veces más de lo necesario.

Mi mejor escenario es una solución que extrae solo una línea del archivo sin leer ninguna de las otras filas en el archivo, pero no puedo pensar en cómo lograría esto en Bash.

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

Estaré usando el time incorporado para comparar cada comando.

Base

Primero veamos cómo head tail solución:

$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0

real    1m15.321s

La línea de base para la fila 50 millones es 00: 01: 15.321, si hubiera ido directamente a la fila 500 millones probablemente serían ~ 12.5 minutos.

cortar

Dudo de este, pero vale la pena intentarlo:

$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0

real    5m12.156s

Este tardó 00: 05: 12.156 en ejecutarse, ¡que es mucho más lento que la línea de base! No estoy seguro de si leyó todo el archivo o solo hasta la línea 50 millones antes de detenerse, pero independientemente de esto, esto no parece una solución viable al problema.

AWK

Solo ejecuté la solución con el exit porque no iba a esperar a que se ejecutara el archivo completo:

$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0

real    1m16.583s

Este código se ejecutó en 00: 01: 16.583, que es solo ~ 1 segundo más lento, pero aún no es una mejora en la línea de base. A este ritmo, si se hubiera excluido el comando de salida, probablemente habría tardado unos ~ 76 minutos en leer todo el archivo.

Perl

También ejecuté la solución Perl existente:

$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0

real    1m13.146s

Este código se ejecutó en 00: 01: 13.146, que es ~ 2 segundos más rápido que la línea de base. Si lo ejecutara en el total de 500,000,000, probablemente tomaría ~ 12 minutos.

SED

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

$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0

real    1m12.705s

Este código se ejecutó en 00: 01: 12.705, que es 3 segundos más rápido que la línea de base y ~ 0.4 segundos más rápido que Perl. Si lo hubiera ejecutado en las 500,000,000 filas completas, probablemente habría tardado ~ 12 minutos.

mapfile

Tengo bash 3.1 y, por lo tanto, no puedo probar la solución del archivo de mapas.

En resumen

Parece que, en su mayor parte, es difícil mejorar el head tail solución. En el mejor de los casos sed La solución proporciona un aumento de ~ 3% en la 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

Respondido el 05 de junio de 17 a las 01:06

Me pregunto cuánto tiempo tomaría simplemente capturar todo el archivo en / dev / null. (¿Y si esto fuera solo un punto de referencia del disco duro?) - sanmai

Siento un impulso perverso de inclinarme ante tu propiedad de un diccionario de archivos de texto de más de 3 conciertos. Cualquiera que sea la razón, esto abarca la textualidad :) - Perro estable

La sobrecarga de ejecutar dos procesos con head + tail será insignificante para un solo archivo, pero comienza a mostrarse cuando hace esto en muchos archivos. - triples

Con la awk es bastante rápido:

awk 'NR == num_line' file

Cuando esto es cierto, el comportamiento predeterminado de awk es interpretado: {print $0}.


Versiones alternativas

Si su archivo es enorme, será mejor que exit después de leer la línea requerida. De esta forma ahorras tiempo de CPU Vea la comparación de tiempo al final de la respuesta..

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

Si desea dar el número de línea de una variable bash, puede usar:

awk 'NR == n' n=$num file
awk -v n=$num 'NR == n' file   # equivalent

Vea cuánto tiempo se ahorra usando exit, especialmente si la línea está en la primera parte del archivo:

# Let's create a 10M lines file
for ((i=0; i<100000; i++)); do echo "bla bla"; done > 100Klines
for ((i=0; i<100; i++)); do cat 100Klines; done > 10Mlines

$ time awk 'NR == 1234567 {print}' 10Mlines
bla bla

real    0m1.303s
user    0m1.246s
sys 0m0.042s
$ time awk 'NR == 1234567 {print; exit}' 10Mlines
bla bla

real    0m0.198s
user    0m0.178s
sys 0m0.013s

Entonces, la diferencia es 0.198s vs 1.303s, alrededor de 6 veces más rápido.

contestado el 20 de mayo de 20 a las 16:05

Este método siempre será más lento porque awk intenta dividir el campo. La sobrecarga de la división del campo se puede reducir mediante awk 'BEGIN{FS=RS}(NR == num_line) {print; exit}' file - kvantour

El verdadero poder de awk en este método surge cuando desea concatenar la línea n1 de file1, n2 de file2, n3 o file3 ... awk 'FNR==n' n=10 file1 n=30 file2 n=60 file3. Con GNU awk, esto se puede acelerar usando awk 'FNR==n{print;nextfile}' n=10 file1 n=30 file2 n=60 file3 . - kvantour

@kvantour de hecho, el nextfile de GNU awk es genial para tales cosas. Cómo FS=RS evita la división del campo? - fedorqui 'ASÍ que deja de hacer daño'

FS=RS no evita la división de campos, pero solo analiza los $ 0 y solo asigna un campo porque no hay RS in $0 - kvantour

@kvantour He estado haciendo algunas pruebas con FS=RS y no vi diferencia en los tiempos. ¿Qué tal si hago una pregunta al respecto para que puedas expandirte? ¡Gracias! - fedorqui 'ASÍ que deja de hacer daño'

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

tail -n+N | head -1

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

tail -n+N imprimirá todo a partir de la línea N, head -1 hará que se detenga 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 séptima línea:

head -7 input.txt | tail -1

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

Los más votados sed 'NUMq;d' Es interesante saberlo, pero yo diría que será entendido por menos personas fuera de la caja que la solución de cabeza / cola y también es más lenta que cola / cabeza.

En mis pruebas, ambas versiones de colas / cabezas superaron sed 'NUMq;d' consecuentemente. Eso está en línea con los otros puntos de referencia que se publicaron. Es difícil encontrar un caso en el que las colas / caras fueran realmente malas. Tampoco es sorprendente, ya que se trata de operaciones que cabría esperar que estuvieran muy optimizadas en un sistema Unix moderno.

Para tener una idea sobre las diferencias de rendimiento, estos son los números que obtengo para un archivo enorme (9.3G):

  • tail -n+N | head -1: 3.7 segundos
  • head -N | tail -1: 4.6 segundos
  • sed Nq;d: 18.8 segundos

Los resultados pueden diferir, pero el rendimiento head | tail y tail | head es, en general, comparable para entradas más pequeñas, y sed siempre es más lento por un factor significativo (alrededor de 5x más o menos).

Para reproducir mi punto de referencia, puede intentar lo siguiente, pero tenga en cuenta que creará un archivo 9.3G 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á el resultado de una ejecución en mi máquina (ThinkPad X1 Carbon con un SSD y 16G de memoria). Supongo que en la ejecución final todo vendrá del caché, no del 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

Respondido el 20 de enero de 18 a las 05:01

¿El rendimiento es diferente entre head | tail vs tail | head? ¿O depende de qué línea se está imprimiendo (comienzo del archivo frente al final del archivo)? - Wisbucky

@wisbucky No tengo cifras precisas, pero una desventaja de usar primero la cola seguida de una "cabeza -1" es que necesitas saber la longitud total de antemano. Si no lo sabe, tendrá que contarlo primero, lo que será una pérdida en términos de rendimiento. Otra desventaja es que es menos intuitivo de usar. Por ejemplo, si tiene el número del 1 al 10 y desea obtener la tercera línea, tendrá que usar "tail -3 | head -8". Eso es más propenso a errores que "head -1 | tail -3". - Philipp Claßen

lo siento, debería haber incluido un ejemplo para ser claro. head -5 | tail -1 vs tail -n+5 | head -1. De hecho, encontré otra respuesta que hizo una comparación de prueba y encontré tail | head para ser más rápido. stackoverflow.com/a/48189289 - Wisbucky

@wisbucky ¡Gracias por mencionarlo! Hice algunas pruebas y tengo que estar de acuerdo en que siempre fue un poco más rápido, independientemente de la posición de la línea de lo que vi. Dado eso, cambié mi respuesta y también incluí el punto de referencia en caso de que alguien quiera reproducirlo. - Philipp Claßen

¡Vaya, todas las posibilidades!

Prueba 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 que tenga que probar el nawk or gawk comando).

¿Existe una herramienta que solo imprima esa línea en particular? No es una de las herramientas estándar. Sin embargo, sed es probablemente el más cercano y sencillo de usar.

Respondido 08 ago 13, 18:08

Esta pregunta está etiquetada como Bash, aquí está la forma de hacerlo Bash (≥4): use mapfile con -s (saltar) y -n (recuento) opción.

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

mapfile -s 41 -n 1 ary < file

En este punto, tendrá una matriz ary cuyos campos contienen las líneas de file (incluida la nueva línea final), donde hemos omitido las primeras 41 líneas (-s 41) y se detuvo después de leer una línea (-n 1). Así que esa es realmente la línea 42. Para imprimirlo:

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

Si necesita un rango de líneas, diga el rango 42–666 (inclusive), y diga que no quiere hacer los cálculos usted mismo, e imprímalos en stdout:

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

Si también necesita procesar estas líneas, no es muy conveniente almacenar la nueva línea final. En este caso utilice el -t opción (recortar):

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

Puede hacer que una función lo haga por usted:

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[@]}"
}

¡Sin comandos externos, solo Bash incorporados!

contestado el 18 de mayo de 14 a las 00:05

También puede usar sed print y salir:

sed -n '10{p;q;}' file   # print line 10

Respondido 24 Oct 15, 01:10

La -n La opción desactiva la acción predeterminada para imprimir cada línea, como seguramente lo habría descubierto con un rápido vistazo a la página del manual. - triples

In GNU sed todo el sed las respuestas son aproximadamente a la misma velocidad. Por lo tanto (para GNU sed) esto es lo mejor sed respuesta, ya que ahorraría tiempo para archivos grandes y pequeños enésima línea valores. - agc

También puede usar Perl para esto:

perl -wnl -e '$.== NUM && print && exit;' some.file

Respondido 22 Oct 14, 02:10

Mientras probaba en un archivo con 6,000,000 líneas y recuperaba la línea arbitraria # 2,000,000, este comando fue casi instantáneo y mucho más rápido que las respuestas sed. - No Pastel

Como seguimiento a la muy útil respuesta de evaluación comparativa de CaffeineConnoisseur ... Tenía curiosidad por saber qué tan rápido se comparaba el método 'mapfile' con otros (ya que no se probó), así que probé una comparación de velocidad rápida y sucia como Tengo bash 4 a mano. Lancé una prueba del método "cola | cabeza" (en lugar de cabeza | cola) mencionado en uno de los comentarios en la respuesta principal mientras estaba en ello, mientras la gente cantaba sus alabanzas. No tengo nada parecido al tamaño del archivo de prueba usado; lo mejor que pude encontrar en poco tiempo fue un archivo de pedigrí de 14M (líneas largas separadas por espacios en blanco, poco menos de 12000 líneas).

Versión corta: mapfile aparece más rápido que el método de corte, pero más lento que todo lo demás, así que lo llamaría un fiasco. cola | head, OTOH, parece que podría ser el más rápido, aunque con un archivo de este tamaño la diferencia no es tan sustancial 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!

Respondido el 10 de enero de 18 a las 17:01

La solución más rápida para archivos grandes es siempre tail | head, siempre que las dos distancias:

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

son conocidos. Entonces, podríamos usar esto:

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

howmany es solo el recuento de líneas requerido.

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

Respondido 13 Abr '17, 15:04

Aclare las unidades de S y E, (es decir, bytes, caracteres o líneas). - agc

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

Dado que las longitudes de las líneas son arbitrarias, todos los bytes del archivo antes de la enésima línea necesitas ser leído. Si tiene un archivo enorme o necesita repetir esta tarea muchas veces, y este proceso lleva mucho tiempo, entonces debería pensar seriamente si debería almacenar sus datos de una manera diferente en primer lugar.

La verdadera solución es tener un índice, por ejemplo, al comienzo del archivo, que indique las posiciones donde comienzan las líneas. Puede usar un formato de base de datos o simplemente agregar una tabla al comienzo del archivo. Alternativamente, cree un archivo de índice separado para acompañar su archivo de texto grande.

por ejemplo, puede crear una lista de posiciones de caracteres para nuevas líneas:

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

luego lee con tail, que en realidad seeks directamente al punto apropiado en el archivo!

por ejemplo, para obtener la línea 1000:

tail -c +$(awk 'NR=1000' file.idx) file.txt | head -1
  • Es posible que esto no funcione con caracteres de 2 bytes / multibyte, ya que awk "reconoce los caracteres" pero tail no.
  • No he probado esto en un archivo grande.
  • Ver también esta respuesta.
  • Alternativamente, ¡divida su archivo en archivos más pequeños!

Respondido 12 Oct 17, 13:10

Usando lo que otros mencionaron, quería que esta fuera una función rápida y elegante en mi shell bash.

Crea un archivo: ~/.functions

Agregue el contenido:

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

Luego agregue esto a su ~/.bash_profile:

source ~/.functions

Ahora, cuando abre una nueva ventana de bash, puede simplemente llamar a la función de la siguiente manera:

getline 441 myfile.txt

Respondido el 17 de enero de 18 a las 17:01

No es necesario asignar $1 a otra variable antes de usarla, y está superando cualquier otra variable global line. En Bash, usa local para variables de función; pero aquí, como ya se dijo, probablemente solo haga sed "$1d;q" "$2". (Observe también la cita de "$2".) - triples

Correcto, pero podría ser útil tener un código autodocumentado. - Mark Shust en M.academy

Si tiene varias líneas delimitadas por \ n (normalmente una nueva línea). También puede usar 'cortar':

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

Obtendrá la segunda línea del archivo. -f3 te da la tercera línea.

Respondido el 07 de enero de 16 a las 19:01

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 preservará el orden). Andriy Makukha

Ya hay muchas buenas respuestas. Yo personalmente prefiero awk. Para mayor comodidad, si usa bash, simplemente agregue lo siguiente a su ~/.bash_profile. Y, la próxima vez que inicie sesión (o si obtiene su .bash_profile después de esta actualización), tendrá una nueva función ingeniosa "enésima" disponible para canalizar sus archivos.

Ejecute esto o póngalo en su ~ / .bash_profile (si usa bash) y vuelva a abrir bash (o ejecute source ~/.bach_profile)

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

Luego, para usarlo, simplemente páselo. P.ej,:

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

Respondido 20 Oct 20, 16:10

Guarde dos pulsaciones de teclas, imprima la línea N sin usar corchetes:

sed  -n  Np  <fileName>
      ^   ^
       \   \___ 'p' for printing
        \______ '-n' for not printing by default 

Por ejemplo, para imprimir la línea 100:

sed -n 100p foo.txt      

contestado el 19 de mayo de 21 a las 17:05

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

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

Aquí, la bandera '-e' es para agregar un script al comando que se ejecutará.

Respondido 07 Abr '15, 21:04

Los dos puntos son un error de sintaxis y deben ser un punto y coma. - triples

Después de echar un vistazo la respuesta principal y que el punto de referencia, He implementado una pequeña función de ayuda:

function nth {
    if (( ${#} < 1 || ${#} > 2 )); then
        echo -e "usage: $0 \e[4mline\e[0m [\e[4mfile\e[0m]"
        return 1
    fi
    if (( ${#} > 1 )); then
        sed "$1q;d" $2
    else
        sed "$1q;d"
    fi
}

Básicamente, puedes usarlo de dos maneras:

nth 42 myfile.txt
do_stuff | nth 42

contestado el 12 de mayo de 20 a las 11:05

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

#!/bin/bash
if [ "${1}" == "" ]; 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 [ "${2}" == "" ]; then
    echo "error: blank file name";
    exit 1
fi
sed "${1}q;d" $2;
exit 0

Asegúrese de que sea ejecutable con

$ chmod +x get

Vincularlo para que esté disponible en el PATH con

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

respondido 16 mar '21, 11:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.