bash - ultimas - sed linux eliminar linea
Eliminar la última línea de un archivo en Bash (11)
Usuarios de Mac
Si solo desea que la última línea elimine la salida sin cambiar el archivo, haga
sed -e ''$ d'' foo.txt
Si desea eliminar la última línea del archivo de entrada, haga
sed -i '''' -e ''$ d'' foo.txt
Tengo un archivo, foo.txt
, que contiene las siguientes líneas:
a
b
c
Quiero un comando simple que foo.txt
como resultado que el contenido de foo.txt
sea:
a
b
Para usuarios de Mac:
En Mac, la cabeza -n -1 no funciona. Y, estaba tratando de encontrar una solución simple [sin preocuparme por el tiempo de procesamiento] para resolver este problema solo con los comandos "cabeza" y / o "cola".
Intenté la siguiente secuencia de comandos y me alegré de poder resolverlo simplemente usando el comando "tail" [con las opciones disponibles en Mac]. Entonces, si estás en Mac y quieres usar solo "cola" para resolver este problema, puedes usar este comando:
cat file.txt | cola -r | cola -n +2 | cola -r
Explicación:
1> cola -r: simplemente invierte el orden de las líneas en su entrada
2> cola -n +2: esto imprime todas las líneas a partir de la segunda línea en su entrada
Ambas soluciones están aquí en otras formas. Los encontré un poco más prácticos, claros y útiles:
Utilizando dd:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)/n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
Utilizando Truncate:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)/n" | bc ) ${ORIGINALFILE}
Esta es, con mucho, la solución más rápida y sencilla, especialmente en archivos grandes:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
Si quieres borrar la línea superior usa esto:
tail -n +2 foo.txt
lo que significa líneas de salida a partir de la línea 2.
No use sed
para eliminar líneas de la parte superior o inferior de un archivo; es muy lento si el archivo es grande.
Para eliminar la última línea de un archivo sin leer todo el archivo o reescribir nada , puede usar
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Para eliminar la última línea y también imprimirla en la salida estándar ("pop"), puede combinar ese comando con tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Estos comandos pueden procesar eficientemente un archivo muy grande. Esto es similar e inspirado por la respuesta de Yossi, pero evita el uso de algunas funciones adicionales.
Si va a usar estos repetidamente y desea controlar los errores y algunas otras funciones, puede usar el comando poptail
aquí: https://github.com/donm/evenmoreutils
Ruby (1.9+)
ruby -ne ''BEGIN{prv=""};print prv ; prv=$_;'' file
Tuve problemas con todas las respuestas aquí porque estaba trabajando con un archivo ENORME (~ 300Gb) y ninguna de las soluciones se amplió. Aquí está mi solución:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
En palabras: Averigüe la longitud del archivo con el que desea terminar (longitud del archivo menos longitud de la longitud de su última línea, usando bc
) y, establezca esa posición para que sea el final del archivo (al dd
un byte de /dev/null
en él).
Esto es rápido porque la tail
comienza a leer desde el final, y dd
sobrescribirá el archivo en su lugar en lugar de copiar (y analizar) cada línea del archivo, que es lo que hacen las otras soluciones.
NOTA: ¡Esto elimina la línea del archivo en su lugar! Haga una copia de seguridad o pruebe un archivo ficticio antes de probarlo en su propio archivo.
Usando GNU sed
:
sed -i ''$ d'' foo.txt
La opción -i
no existe en las versiones GNU sed
anteriores a 3.95, por lo que debe usarla como filtro con un archivo temporal:
cp foo.txt foo.txt.tmp
sed ''$ d'' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Por supuesto, en ese caso también puedes usar head -n -1
lugar de sed
.
awk "NR != `wc -l < text.file`" text.file |> text.file
Este fragmento hace el truco.
awk ''NR>1{print buf}{buf = $0}''
Esencialmente, este código dice lo siguiente:
Para cada línea después de la primera, imprima la línea en buffer
Para cada línea, reinicie el búfer.
El búfer está retrasado por una línea, por lo que termina imprimiendo las líneas 1 a n-1
echo -e ''$d/nw/nq''| ed foo.txt