Cómo usar sed para eliminar las últimas n líneas de un archivo

Quiero eliminar algunas n líneas del final de un archivo. ¿Se puede hacer esto usando sed?

Por ejemplo, para eliminar líneas del 2 al 4, puedo usar

$ sed '2,4d' file 

Pero no sé los números de línea. Puedo eliminar la última línea usando

 $sed $d file 

pero quiero saber la forma de eliminar n líneas del final. Por favor, hágamelo saber cómo usar sed o algún otro método.

No sé sobre sed , pero se puede hacer con la head :

 head -n -2 myfile.txt 

De los sed one-liners :

 # delete the last 10 lines of a file sed -e :a -e '$d;N;2,10ba' -e 'P;D' # method 1 sed -n -e :a -e '1,10!{P;N;D;};N;ba' # method 2 

Parece ser lo que estás buscando.

Una solución graciosa y simple sed y tac :

 n=4 tac file.txt | sed "1,$n{d}" | tac 

NOTA

  • comillas dobles " son necesarias para que el shell evalúe la variable $n en el comando sed . En comillas simples, no se realizará la interpolación.
  • tac es un cat invertido, ver man 1 tac
  • {} in sed están ahí para separar $n & d (si no, el shell trata de interpolar la variable $nd no existente)

Si hardcoding n es una opción, puede usar llamadas secuenciales a sed. Por ejemplo, para eliminar las últimas tres líneas, elimine la última línea tres veces:

 sed '$d' file | sed '$d' | sed '$d' 

Usa sed , pero deja que el shell haga los cálculos, con el objective de usar el comando d dando un rango (para eliminar las últimas 23 líneas):

 sed -i "$(($(wc -l < file)-22)),\$d" file 

Para eliminar las últimas 3 líneas, de adentro hacia afuera:

 $(wc -l < file) 

Da el número de líneas del archivo: digamos 2196

Queremos eliminar las últimas 23 líneas, por lo que para el lado izquierdo o el rango:

 $((2196-22)) 

Da: 2174 Por lo tanto, la interpretación original de sed tras capa es:

 sed -i 2174,$d file 

Con -i haciendo edit in place, ¡el archivo ahora tiene 2173 líneas!

Puedes usar cabeza para esto.

Utilizar

$ head --lines=-N file > new_file

donde N es el número de líneas que desea eliminar del archivo.

El contenido del archivo original menos las últimas N líneas ahora está en new_file

Solo para completar, me gustaría agregar mi solución. Terminé haciendo esto con la ed estándar:

 ed -s sometextfile < << $'-2,$d\nwq' 

Esto borra las últimas 2 líneas usando la edición in situ (¡¡¡aunque utiliza un archivo temporal en /tmp !!)

Esto podría funcionar para usted (GNU sed):

 sed ':a;$!N;1,4ba;P;$d;D' file 

Para truncar realmente los archivos muy grandes, tenemos un comando truncate . No sabe sobre líneas, pero tail + wc puede convertir líneas en bytes:

 file=bigone.log lines=3 truncate -s -$(tail -$lines $file | wc -c) $file 

Existe una condición de carrera obvia si el archivo se escribe al mismo tiempo. En este caso, puede ser mejor usar head : cuenta los bytes desde el principio del archivo (mind disk IO), por lo que siempre truncaremos el límite en línea (posiblemente más líneas de lo esperado si el archivo está escrito activamente):

 truncate -s $(head -n -$lines $file | wc -c) $file 

Handy one-liner si no inicia sesión intente poner la contraseña en lugar del nombre de usuario:

 truncate -s $(head -n -5 /var/log/secure | wc -c) /var/log/secure 

Con las respuestas aquí, ya habrás aprendido que sed no es la mejor herramienta para esta aplicación.

Sin embargo, creo que hay una forma de hacer esto al usar sed; la idea es agregar N líneas para mantener el espacio hasta que puedas leer sin tocar EOF. Cuando se golpea EOF, imprima el contenido del espacio de espera y salga.

 sed -e '$!{N;N;N;N;N;N;H;}' -ex 

El comando sed de arriba omitirá las últimas 5 líneas.

La mayoría de las respuestas anteriores parecen requerir comandos / extensiones de GNU:

  $ head -n -2 myfile.txt -2: Badly formed number 

Para una solución ligeramente más portable:

  perl -ne 'push(@fifo,$_);print shift(@fifo) if @fifo > 10;' 

O

  perl -ne 'push(@buf,$_);END{print @buf[0 ... $#buf-10]}' 

O

  awk '{buf[NR-1]=$0;}END{ for ( i=0; i < (NR-10); i++){ print buf[i];} }' 

Donde "10" es "n".

Pruebe el siguiente comando:

 n = line number tail -r file_name | sed '1,nd' | tail -r 

Puede obtener el recuento total de líneas con wc -l y usar

head -n

Se puede hacer en 3 pasos:

a) Cuente el número de líneas en el archivo que desea editar:

  n=`cat myfile |wc -l` 

b) Resta de ese número el número de líneas para eliminar:

  x=$((n-3)) 

c) Tell sed para eliminar de ese número de línea ( $x ) hasta el final:

  sed "$x,\$d" myfile 

Yo prefiero esta solución;

 head -$(gcalctool -s $(cat file | wc -l)-N) file 

donde N es el número de líneas para eliminar.

 sed -n ':pre 1,4 {N;b pre } :cycle $!{P;N;D;b cycle }' YourFile 

posix versión

Para eliminar las últimas 4 líneas:

 $ nl -ba file | sort -k1,1nr | sed '1, 4 d' | sort -k1,1n | sed 's/^ *[0-9]*\t//' 

Se me ocurrió esto, donde n es el número de líneas que desea eliminar:

 count=`wc -l file` lines=`expr "$count" - n` head -n "$lines" file > temp.txt mv temp.txt file rm -f temp.txt 

Es una pequeña rotonda, pero creo que es fácil de seguir.

  1. Cuente el número de líneas en el archivo principal
  2. Reste la cantidad de líneas que desea eliminar del recuento
  3. Imprima la cantidad de líneas que desea conservar y almacene en un archivo temporal
  4. Reemplace el archivo principal con el archivo temporal
  5. Eliminar el archivo temporal

Esto eliminará las últimas 3 líneas del file :

for i in $(seq 1 3); do sed -i '$d' file; done;

Esto eliminará las últimas 12 líneas

 sed -n -e :a -e '1,10!{P;N;D;};N;ba'