Tengo algunos archivos que me gustaría eliminar la última línea nueva si es el último carácter de un archivo. od -c
me muestra que el comando que ejecuto escribe el archivo con una nueva línea al final:
0013600 n t > \n
He intentado algunos trucos con sed, pero lo mejor que se me ocurre no es hacer el truco:
sed -e '$s/\(.*\)\n$/\1/' abc
¿Alguna idea de como hacer esto?
\n
, en Linux es un personajeRespuestas:
o, para editar el archivo en su lugar:
[Nota del editor:
-pi -e
fue originalmente-pie
, pero, como lo señalaron varios comentaristas y lo explicó @hvd, este último no funciona].Esto fue descrito como una 'blasfemia perl' en el sitio web awk que vi.
Pero, en una prueba, funcionó.
fuente
chomp
. Y es mejor sorber el archivo.perl -pi -e 'chomp if eof' filename
, para editar un archivo en el lugar en lugar de crear un archivo temporalperl -pie 'chomp if eof' filename
-> No se puede abrir el script de perl "chomp if eof": No existe tal archivo o directorio;perl -pi -e 'chomp if eof' filename
-> funcionaPuede aprovechar el hecho de que las sustituciones de comandos de shell eliminan los caracteres de nueva línea finales :
Forma simple que funciona en bash, ksh, zsh:
Alternativa portátil (compatible con POSIX) (ligeramente menos eficiente):
Nota:
in.txt
extremos con múltiples caracteres de nueva línea, la sustitución de comandos elimina todas ellas - gracias, @Sparhawk. (No elimina los caracteres de espacio en blanco que no sean líneas nuevas al final).printf %s
garantiza que no se agregue una nueva línea a la salida (es la alternativa compatible con POSIX a la no estándarecho -n
; consulte http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html y https: //unix.stackexchange. com / a / 65819 )Una guía para las otras respuestas :
Si Perl está disponible, busque la respuesta aceptada : es simple y eficiente en la memoria (no lee todo el archivo de entrada de una vez).
De lo contrario, considere la respuesta Awk de ghostdog74 : es oscura, pero también eficiente en memoria ; un equivalente más legible (compatible con POSIX) es:
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
bloque, donde se imprime sin un final\n
debido a la configuración del separador de registro de salida (OFS
) en una cadena vacía.Si desea una solución detallada, rápida y robusta que realmente edite en el lugar (en lugar de crear un archivo temporal que luego reemplace el original), considere el script Perl de jrockway .
fuente
Puede hacer esto con los
head
coreutils de GNU, admite argumentos relacionados con el final del archivo. Entonces, para dejar de usar el último byte:Para probar una nueva línea final, puede usar
tail
ywc
. El siguiente ejemplo guarda el resultado en un archivo temporal y posteriormente sobrescribe el original:También puede usar
sponge
desdemoreutils
para hacer la edición "in situ":También puede hacer una función reutilizable general rellenando esto en su
.bashrc
archivo:Actualizar
Como señaló KarlWilbur en los comentarios y utilizado en la respuesta de Sorentar ,
truncate --size=-1
puede reemplazarhead -c-1
y admite la edición en el lugar.fuente
truncate --size=-1
lugar de hacerlo,head -c -1
ya que solo cambia el tamaño del archivo de entrada en lugar de leerlo, escribirlo en otro archivo y luego reemplazar el original con el archivo de salida.head -c -1
eliminará el último carácter independientemente de si es una nueva línea o no, es por eso que debe verificar si el último carácter es una nueva línea antes de eliminarlo.Edición 2:Aquí hay unaawk
versión (corregida) que no acumula una matriz potencialmente enorme:awk '{if (línea) línea de impresión; line = $ 0} END {printf $ 0} 'abcfuente
awk
versión. Se necesitan dos compensaciones (y una prueba diferente) y solo usé una. Sin embargo, podría usar enprintf
lugar deORS
.head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
papar moscas
fuente
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file
Esto debería ser más fácil de leer.awk 'NR>1 {print p} {p=$0} END {printf $0}' file
.printf
es el argumento de formato . Por lo tanto, si el archivo de entrada tuviera algo que pudiera interpretarse como un especificador de formato%d
, obtendría un error. Una solución sería cambiar aprintf "%s" $0
Un método muy simple para archivos de una sola línea, que requiere eco GNU de coreutils:
fuente
\n
está presente. A medida que se convierte en una nueva línea.$(...)
se cita/bin/echo -n "$(cat infile)"
Además, no estoy seguro de cuál sería el máximo de lenecho
o el shell en las versiones de os / shell / distros (solo buscaba en Google esto y era un agujero de conejo), así que estoy no estoy seguro de qué tan portátil (o eficiente) sería en realidad para cualquier cosa que no sean archivos pequeños, pero para archivos pequeños, genial.Si quieres hacerlo bien, necesitas algo como esto:
Abrimos el archivo para leer y agregar; abrir para agregar significa que ya estamos
seek
editados al final del archivo. Luego obtenemos la posición numérica del final del archivo contell
. Usamos ese número para buscar un carácter, y luego leemos ese carácter. Si se trata de una nueva línea, truncamos el archivo al carácter antes de esa nueva línea; de lo contrario, no hacemos nada.Esto se ejecuta en tiempo constante y espacio constante para cualquier entrada, y tampoco requiere más espacio en disco.
fuente
Aquí hay una buena y ordenada solución de Python. No hice ningún intento de ser conciso aquí.
Esto modifica el archivo en el lugar, en lugar de hacer una copia del archivo y quitar la nueva línea de la última línea de la copia. Si el archivo es grande, será mucho más rápido que la solución Perl elegida como la mejor respuesta.
Trunca un archivo en dos bytes si los dos últimos bytes son CR / LF, o en un byte si el último byte es LF. No intenta modificar el archivo si los últimos bytes no son (CR) LF. Maneja errores. Probado en Python 2.6.
Ponga esto en un archivo llamado "striplast" y
chmod +x striplast
.PD: En el espíritu del "Perl golf", aquí está mi solución Python más corta. Extrae todo el archivo de la entrada estándar a la memoria, elimina todas las líneas nuevas del final y escribe el resultado en la salida estándar. No tan conciso como el Perl; simplemente no puedes vencer a Perl por pequeñas cosas rápidas como esta.
Elimine el "\ n" de la llamada
.rstrip()
y eliminará todo el espacio en blanco desde el final del archivo, incluidas varias líneas en blanco.Pon esto en "slurp_and_chomp.py" y luego ejecuta
python slurp_and_chomp.py < inputfile > outputfile
.fuente
Una solución rápida es usar la utilidad gnu
truncate
:La prueba será verdadera si el archivo tiene una nueva línea final.
La eliminación es muy rápida, realmente en su lugar, no se necesita ningún archivo nuevo y la búsqueda también lee desde el final solo un byte (
tail -c1
).fuente
[ -z $(tail -c1 filename) ] && truncate -s -1 filename
(también, en respuesta al otro comentario, eltruncate
comando no funciona con stdin, se requiere un nombre de archivo)Otro perl WTDI:
fuente
Consulte también Hacer coincidir cualquier carácter (incluidas las nuevas líneas) en sed .
fuente
tr -d '\n'
Usando dd:
fuente
fuente
g
o los paréntesis alrededoreof
:perl -pi -e 's/\n$// if eof' your_file
.Asumiendo el tipo de archivo Unix y solo desea la última línea nueva, esto funciona.
No funcionará en múltiples líneas nuevas ...
* Funciona solo si la última línea es una línea en blanco.
fuente
sed
solución que funciona incluso para una última línea que no está en blanco: stackoverflow.com/a/52047796Sin embargo, otra respuesta FTR (¡y mi favorita!): Echo / cat lo que quieres quitar y capturar la salida a través de backticks. La nueva línea final será eliminada. Por ejemplo:
fuente
POSIX SED:
'$ {/ ^ $ / d}'
fuente
echo -en 'a\nb\n' | sed '${/^$/d}'
no eliminará nada.echo -en 'a\nb\n\n' | sed '${/^$/d}'
se eliminará ya que toda la última línea está en blanco.Esta es una buena solución si necesita que funcione con tuberías / redirección en lugar de lectura / salida desde o hacia un archivo. Esto funciona con líneas simples o múltiples. Funciona si hay una nueva línea final o no.
Detalles:
head -c -1
trunca el último carácter de la cadena, independientemente de cuál sea el carácter. Entonces, si la cadena no termina con una nueva línea, entonces estaría perdiendo un carácter.sed '$s/$//'
. El primer$
medio solo aplica el comando a la última línea.s/$//
significa sustituir el "final de la línea" con "nada", que básicamente no hace nada. Pero tiene un efecto secundario de agregar una nueva línea final si no hay una.Nota: el valor predeterminado de Mac
head
no admite la-c
opción. Puedes hacerbrew install coreutils
y usarghead
en su lugar.fuente
La única vez que he querido hacer esto es para el código golf, y luego simplemente copié mi código del archivo y lo pegué en una
echo -n 'content'>file
declaración.fuente
fuente
Tuve un problema similar, pero estaba trabajando con un archivo de Windows y necesito mantener esos CRLF: mi solución en Linux:
fuente
Debería eliminar cualquier última aparición de \ n en el archivo. No funciona en archivos grandes (debido a la limitación del búfer de sed)
fuente
rubí:
o:
fuente