resumen
Imprima líneas sin nueva línea, agregue una nueva línea solo si hay otra línea para imprimir.
$ printf 'one\ntwo\n' |
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
Otras soluciones
Si estuviéramos trabajando con un archivo, podemos truncar un carácter de él (si termina en una nueva línea):
removeTrailNewline () {[[$ (tail -c 1 "$ 1")]] || truncar -s-1 "$ 1"; }
Esa es una solución rápida, ya que necesita leer solo un carácter del archivo y luego eliminarlo directamente ( truncate
) sin leer todo el archivo.
Sin embargo, al trabajar con datos de stdin (una secuencia), los datos deben leerse, todo. Y, se "consume" tan pronto como se lee. Sin retroceso (como con truncar). Para encontrar el final de una secuencia necesitamos leer hasta el final de la secuencia. En ese punto, no hay forma de retroceder en la secuencia de entrada, los datos ya se han "consumido". Esto significa que los datos deben almacenarse en alguna forma de búfer hasta que coincidamos con el final de la secuencia y luego hacer algo con los datos en el búfer.
La solución más obvia es convertir la secuencia en un archivo y procesar ese archivo. Pero la pregunta pide algún tipo de filtro de la corriente. No se trata del uso de archivos adicionales.
variable
La solución ingenua sería capturar toda la entrada en una variable:
FilterOne(){ filecontents=$(cat; echo "x"); # capture the whole input
filecontents=${filecontents%x}; # Remove the "x" added above.
nl=$'\n'; # use a variable for newline.
printf '%s' "${filecontents%"$nl"}"; # Remove newline (if it exists).
}
printf 'one\ntwo' | FilterOne ; echo 1done
printf 'one\ntwo\n' | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done
memoria
Es posible cargar un archivo completo en la memoria con sed. En sed es imposible evitar la nueva línea final en la última línea. GNU sed podría evitar imprimir una nueva línea final, pero solo si el archivo fuente ya no se encuentra. Entonces, no, sed simple no puede ayudar.
Excepto en GNU awk con la -z
opción:
sed -z 's/\(.*\)\n$/\1/'
Con awk (cualquier awk), sorbe toda la secuencia y printf
sin la nueva línea final.
awk ' { content = content $0 RS }
END { gsub( "\n$", "", content ); printf( "%s", content ) }
'
Cargar un archivo completo en la memoria puede no ser una buena idea, puede consumir mucha memoria.
Dos líneas en la memoria
En awk, podemos procesar dos líneas por ciclo almacenando la línea anterior en una variable e imprimiendo la actual:
awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'
Procesamiento directo
Pero podríamos hacerlo mejor.
Si imprimimos la línea actual sin una nueva línea e imprimimos una nueva línea solo cuando existe una línea siguiente, procesamos una línea a la vez y la última línea no tendrá una nueva línea final:
awk 'NR == 1 {printf ("% s", $ 0); siguiente}; {printf ("\ n% s", $ 0)} '
O, escrito de alguna otra manera:
awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'
O:
awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'
Entonces:
$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
chomp
, ya quechomp
solo elimina a lo sumo una nueva línea final.