Tengo archivos que terminan en una o más líneas nuevas y deberían terminar en una sola línea nueva. ¿Cómo puedo hacer eso con las herramientas Bash / Unix / GNU?
Ejemplo de archivo incorrecto:
1\n
\n
2\n
\n
\n
3\n
\n
\n
\n
Archivo corregido de ejemplo:
1\n
\n
2\n
\n
\n
3\n
En otras palabras: debe haber exactamente una nueva línea entre el EOF y el último carácter que no sea de nueva línea del archivo.
Implementación de referencia
Lea el contenido del archivo, corte una línea nueva hasta que no haya más líneas nuevas al final, escríbala de nuevo:
#! /bin/python
import sys
with open(sys.argv[1]) as infile:
lines = infile.read()
while lines.endswith("\n\n"):
lines = lines[:-1]
with open(sys.argv[2], 'w') as outfile:
for line in lines:
outfile.write(line)
Aclaración: Por supuesto, se permite la tubería, si eso es más elegante.
sed
propuesta que acaba de ocurrir ... OMGawk: illegal statement
.brew install mawk
y cambiar el comando amawk
funciona sin embargo.De útiles scripts de una línea para sed .
fuente
find . -type f -name '*.js' -exec sed --in-place -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
find . -type f -name '*.js' -exec sed -i '' -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
Dado que ya tiene respuestas con las herramientas más adecuadas sed y awk; podría aprovechar el hecho de que
$(< file)
elimina las líneas en blanco al final.Ese truco barato no funcionaría para eliminar las líneas en blanco finales que pueden contener espacios u otros caracteres que no se imprimen, solo para eliminar las líneas vacías finales. Tampoco funcionará si el archivo contiene bytes nulos.
En shells que no sean bash y zsh, use en
$(cat file)
lugar de$(<file)
.fuente
$()
descarta las nuevas líneas finales. Esa es una decisión de diseño. Supongo que esto facilitará la integración en otras cadenas:echo "On $(date ...) we will meet."
sería malo con la nueva línea que casi todos los comandos de shell salen al final.[[ $a == '' ]] || printf '%s\n' "$a" >"$file"
.a=$(gtac file.txt); printf '%s\n' "$a" | gtac > file.txt
Puedes usar este truco con
cat
&printf
:Por ejemplo
los
$
denota el final de una línea.Referencias
fuente
Esta pregunta está etiquetada con ed , pero nadie ha propuesto un
ed
solución.Aquí hay uno:
o equivalente,
ed
lo colocará en la última línea del búfer de edición de forma predeterminada al inicio.El primer comando (
a
) agrega una línea vacía al final del búfer (la línea vacía en el script de edición es esta línea y el punto (.
) es solo para volver al modo de comando).El segundo comando (
?
) busca la línea anterior más cercana que contiene algo (incluso caracteres de espacio en blanco), y luego elimina todo al final del búfer desde la siguiente línea.El tercer comando (
w
) vuelve a escribir el archivo en el disco.La línea vacía agregada protege el resto del archivo para que no se elimine en caso de que no haya líneas vacías al final del archivo original.
fuente
Aquí hay una solución de Perl que no requiere leer más de una línea en la memoria a la vez:
o, como una línea:
Esto lee el archivo línea por línea y verifica cada línea para ver si contiene un carácter que no sea de línea nueva. Si no lo hace, incrementa un contador; si lo hace, imprime el número de líneas nuevas indicadas por el contador, seguido de la línea misma, y luego restablece el contador.
Técnicamente, incluso el almacenamiento en búfer de una sola línea en la memoria es innecesario; Sería posible resolver este problema utilizando una cantidad constante de memoria leyendo el archivo en fragmentos de longitud fija y procesándolo carácter por carácter utilizando una máquina de estado. Sin embargo, sospecho que sería innecesariamente complicado para el caso de uso típico.
fuente
Si su archivo es lo suficientemente pequeño como para deslizarse en la memoria, puede usar esto
fuente
En python (sé que no es lo que quieres, pero es mucho mejor ya que está optimizado y es un preludio de la versión bash) sin reescribir el archivo y sin leer todo el archivo (lo cual es bueno si el archivo es muy grande):
Tenga en cuenta que no funciona en archivos donde el carácter EOL no es '\ n'.
fuente
Una versión bash, que implementa el algoritmo python, pero menos eficiente ya que necesita muchos procesos:
fuente
Este es rápido de escribir y, si sabe sed, fácil de recordar:
Se utiliza la secuencia de comandos sed para eliminar las principales líneas en blanco de uno útil para scripts de línea de sed , referenciados por Alexey, arriba, y tac (cat inversa).
En una prueba rápida, en un archivo de 18 MB y 64,000 líneas, el enfoque de Alexey fue más rápido (0.036 vs 0.046 segundos).
fuente