¿Qué es lo contrario de la cabeza? Quiero todas menos las primeras N líneas de un archivo


142

Dado un archivo de texto de longitud desconocida, ¿cómo puedo leer, por ejemplo, todas menos las 2 primeras líneas del archivo? Sé tailque me dará las últimas N líneas, pero no sé qué es N antes de tiempo.

Entonces para un archivo

AAAA
BBBB
CCCC
DDDD
EEEE

quiero

CCCC
DDDD
EEEE

Y para un archivo

AAAA
BBBB
CCCC

Solo obtendria

CCCC

Respuestas:


211

tail --help da lo siguiente:

  -n, --lines=K            output the last K lines, instead of the last 10;
                           or use -n +K to output lines starting with the Kth

Entonces, para filtrar las primeras 2líneas, -n +3debería darle la salida que está buscando (comience desde el 3er).


2
Curiosamente, mi página de manual no incluye la opción, pero funciona bien, ¡gracias!
Nicholas MT Elliott

@Nicholas: Extraño, pensé que sería una documentación estándar independientemente del sistema operativo. Saqué eso de Cygwin dentro de Windows, así que no sé cómo se ve en varias distribuciones de Linux. Me alegro de que funcionó.
Joe Enos

@NicholasMTElliott man7 lo enumera como la página de manual de Joe Enos, por lo que es probable que sea un problema con la versión de la página de manual
Uli Köhler

@SteveJorgensen: No entiendo a qué se refiere tu comentario; nadie parece estar sugiriendo usar headpara esto?
ruakh

22

Suponiendo que su versión de tail lo admita, puede especificar comenzar la cola después de X líneas. En tu caso, harías 2 + 1.

tail -n +3

[mdemaria@oblivion ~]$ tail -n +3 stack_overflow.txt
CCCC
DDDD
EEEE

12

Una solución simple usando awk:

awk 'NR > 2 { print }' file.name

Uno de nosotros está confundido. Las preguntas dicen: "todas menos las 2 primeras líneas del archivo". ¿Cómo ese comando no cumple con el requisito?
enero

66
{ print }es la acción predeterminada y se puede omitir.
tripleee

8

Tratar sed 1,2d. Reemplace 2 según sea necesario.


funcionó como se esperaba ... ya que se desconoce el número de líneas después de las primeras 2 líneas.
kumarprd

6

tail -n +linecount filenamecomenzará a salir en la línea linecountde filename, por tail -n +3 filename lo que debe hacer lo que desee.


Esto no funcionaría en mi caparazón, pero lo tail -n +17 filenameharía. Yo uso bash / ubuntu LTS
isomorphismes

2
@iso: Gracias por el aviso: las versiones anteriores de tailaceptaron la sintaxis que usé en mi respuesta original, pero ahora hay que usar la -nopción explícita . He actualizado mi respuesta en consecuencia.
Jim Lewis

0

Use esto, suponiendo que la primera muestra se llame sample1.dat y luego tail --lines=3 sample1.datimprima todas las líneas desde la tercera línea hasta la última.

Para la segunda muestra, supongamos de nuevo que se llama sample2.dat, que sería la tail --lines=-1 sample2.datque imprimiría la última línea ...


@ Jim: ¿cuál es la diferencia con la tuya y la mía? ... lo mismo ...: o Me refería a las dos entradas de archivo de datos de muestra según su pregunta y le mostraba cómo lograr lo que estaba buscando ... .
t0mm13b

Ok ... entonces, ¿por qué pidió la segunda muestra y mostró el resultado que quería, que es lo que usé 'tail --lines = -1' ...... por supuesto, puede omitir el nombre de archivo por completo y todavía puede actuar como una tubería ... hmm
t0mm13b

@tommie: Vaya, olvide lo que dije sobre las tuberías ... Debo haber estado pensando en alguna otra utilidad. Pero mi punto fue que un solo comando, tail +3 anyfileda los resultados deseados para el caso general, mientras que tail --lines=Nrequiere conocer N de antemano para dar el resultado deseado.
Jim Lewis

@tommie: Pero esto es tail... ¿no debería ser "de abajo hacia arriba"? (Ba-dum TISH! Gracias, estaré aquí toda la semana ...)
Jim Lewis

0

Realmente no sé cómo hacerlo desde la cola o la cabeza, pero con la ayuda de wc -l(recuento de líneas) y la expresión bash, puedes lograrlo.

tail -$(( $( wc -l $FILE | grep -Eo '[0-9]+' ) - 2 )) $FILE

Espero que esto ayude.


1
Esto requiere un pase completo sobre el archivo antes de ejecutar tail. Si el archivo es mayor que el tamaño de la memoria, esto será muy ineficiente. No maneja archivos de menos de dos líneas. No maneja el tamaño de cambio de archivo entre el wc y la cola.
enero

2
@janm: Estás bien. Otras respuestas son simplemente mejores. Me siento avergonzado :-p
NawaMan

-1

usando awk para obtener todas menos las últimas 2 líneas

awk 'FNR==NR{n=FNR}FNR<=n-3{print}' file file

awk para obtener todo menos las primeras 2 líneas

awk 'NR>2' file

O puedes usar más

more +2 file

o simplemente golpear

#!/bin/bash

i=0
while read -r line
do
  [[ $i > 1 ]] && echo "$line"
  ((i++))
done <"file"

Ahora esto no cumple con el requisito. La pregunta dice "todas menos las 2 primeras líneas del archivo" y da dos ejemplos, cada uno con un solo archivo, donde se omiten las dos primeras líneas y el resto del archivo se envía a stdout. Eso no es lo que hace este comando.
janm

Sí, leí mal la pregunta. pensé que es pedir todas menos las últimas 2 líneas.
ghostdog74
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.