¿Cómo puedo reemplazar cada nueva línea (\n) con un espacio usando sed?

Resuelto hhh asked hace 15 años • 43 respuestas

¿Cómo puedo reemplazar una nueva línea (" \n") con un espacio (" ") usando el sedcomando?

Intenté sin éxito:

sed 's#\n# #g' file
sed 's#^$# #g' file

¿Cómo lo soluciono?

hhh avatar Aug 10 '09 02:08 hhh
Aceptado

sedestá diseñado para usarse en entradas basadas en líneas. Aunque puede hacer lo que necesitas.


Una mejor opción aquí es usar el trcomando de la siguiente manera:

tr '\n' ' ' < input_filename

o eliminar los caracteres de nueva línea por completo:

tr -d '\n' < input.txt > output.txt

o si tienes la versión GNU (con sus opciones largas)

tr --delete '\n' < input.txt > output.txt

Utilice esta solución con GNU sed:

sed ':a;N;$!ba;s/\n/ /g' file

Esto leerá el archivo completo en un bucle ( ':a;N;$!ba) y luego reemplazará las nuevas líneas con un espacio ( s/\n/ /g). Si es necesario, simplemente se pueden agregar sustituciones adicionales.

Explicación:

  1. sedcomienza leyendo la primera línea excluyendo la nueva línea en el espacio del patrón.
  2. Crea una etiqueta mediante :a.
  3. Agregue una nueva línea y la siguiente línea al espacio del patrón mediante N.
  4. Si estamos antes de la última línea, pase a la etiqueta creada $!ba( $!significa no hacerlo en la última línea. Esto es necesario para evitar ejecutar Nnuevamente, lo que terminaría el script si no hay más entradas).
  5. Finalmente, la sustitución reemplaza cada nueva línea con un espacio en el espacio del patrón (que es el archivo completo).

Aquí hay una sintaxis compatible multiplataforma que funciona con BSD y OS X sed(según el comentario de @Benjie ):

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

Como puede ver, usar sedpara este problema que de otro modo sería simple es problemático. Para obtener una solución más sencilla y adecuada, consulte esta respuesta .

Zsolt Botykai avatar Aug 09 '2009 20:08 Zsolt Botykai

Respuesta rápida

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a crea una etiqueta 'a'
  2. N agregue la siguiente línea al espacio del patrón
  3. ps si no es la última línea , rama ba (ir a) etiqueta 'a'
  4. s sustituto , /\n/ expresión regular para nueva línea , // por un espacio , /g coincidencia global (tantas veces como sea posible)

sed recorrerá los pasos 1 a 3 hasta llegar a la última línea, haciendo que todas las líneas encajen en el espacio del patrón donde sed sustituirá todos los caracteres \n


Alternativas

Todas las alternativas, a diferencia de sed , no necesitarán llegar a la última línea para comenzar el proceso.

con bash , lento

while read line; do printf "%s" "$line "; done < file

con perl , velocidad similar a sed

perl -p -e 's/\n/ /' file

con tr , más rápido que sed , se puede reemplazar con un solo carácter

tr '\n' ' ' < file

con pegar , velocidad similar a tr , se puede reemplazar por un solo carácter

paste -s -d ' ' file

con velocidad tipo awk , tr

awk 1 ORS=' ' file

Otra alternativa como "echo $(< file)" es lenta, funciona sólo en archivos pequeños y necesita procesar el archivo completo para comenzar el proceso.


Respuesta larga de las preguntas frecuentes de sed 5.10

5.10. ¿Por qué no puedo hacer coincidir o eliminar una nueva línea usando la
secuencia de escape \n? ¿Por qué no puedo hacer coincidir 2 o más líneas usando \n?

\n nunca coincidirá con la nueva línea al final de la línea porque la
nueva línea siempre se elimina antes de colocar la línea en el
espacio del patrón. Para colocar 2 o más líneas en el espacio del patrón, use
el comando 'N' o algo similar (como 'H;...;g;').

Sed funciona así: sed lee una línea a la vez, corta la
nueva línea final, coloca lo que queda en el espacio del patrón donde
el script sed puede abordarlo o cambiarlo, y cuando
se imprime el espacio del patrón, agrega una nueva línea a la salida estándar. (o a un archivo). Si el
espacio del patrón se elimina total o parcialmente con 'd' o 'D', la nueva línea no
se agrega en tales casos. Así, guiones como

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

NUNCA funcionará, porque la nueva línea final se elimina antes de que
la línea se coloque en el espacio del patrón. Para realizar las tareas anteriores,
utilice uno de estos scripts:

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Dado que las versiones de sed distintas a GNU sed tienen límites en el tamaño del
búfer de patrones, aquí se prefiere la utilidad 'tr' de Unix.
Si la última línea del archivo contiene una nueva línea, GNU sed agregará
esa nueva línea a la salida pero eliminará todas las demás, mientras que tr eliminará
todas las nuevas líneas.

Para hacer coincidir un bloque de dos o más líneas, existen 3 opciones básicas:
(1) usar el comando 'N' para agregar la siguiente línea al espacio del patrón;
(2) use el comando 'H' al menos dos veces para agregar la línea actual
al espacio de retención y luego recupere las líneas del espacio de retención
con x, g o G; o (3) utilizar rangos de direcciones (consulte la sección 3.3, arriba)
para hacer coincidir líneas entre dos direcciones especificadas.

Las opciones (1) y (2) colocarán un \n en el espacio del patrón, donde se
puede abordar como se desee ('s/ABC\nXYZ/alphabet/g'). Un ejemplo
del uso de 'N' para eliminar un bloque de líneas aparece en la sección 4.13
("¿Cómo elimino un bloque de líneas consecutivas específicas ?"). Este
ejemplo se puede modificar cambiando el comando de eliminación por otro
, como 'p' (imprimir), 'i' (insertar), 'c' (cambiar), 'a' (añadir)
o 's' (sustituir). .

La opción (3) no colocará un \n en el espacio del patrón, pero sí coincidirá
con un bloque de líneas consecutivas, por lo que es posible que ni
siquiera necesites el \n para encontrar lo que estás buscando. Dado que GNU sed
versión 3.02.80 ahora admite esta sintaxis:

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

Además de las
direcciones de rango tradicionales '/desde aquí/,/hasta allí/{...}', es posible evitar el uso de \n por completo.

hdorio avatar Oct 08 '2011 14:10 hdorio

GNU sed tiene una opción, -zpara registros (líneas) separados por nulos. Puedes simplemente llamar:

sed -z 's/\n/ /g'
JJoao avatar May 05 '2015 09:05 JJoao

Una alternativa awk más corta:

awk 1 ORS=' '

Explicación

Un programa awk se compone de reglas que constan de bloques de código condicionales, es decir:

condition { code-block }

Si se omite el bloque de código, se utiliza el valor predeterminado: { print $0 }. Por lo tanto, se 1interpreta como una condición verdadera y print $0se ejecuta para cada línea.

Cuando awklee la entrada, la divide en registros según el valor de RS(Separador de registros), que de forma predeterminada es una nueva línea, por lo que awkanalizará la entrada de forma predeterminada. La división también implica eliminar RSel registro de entrada.

Ahora, al imprimir un registro, ORSse le agrega (Separador de registros de salida), el valor predeterminado es nuevamente una nueva línea. Entonces, al cambiar ORSa un espacio, todas las nuevas líneas se convierten en espacios.

Thor avatar Feb 13 '2013 12:02 Thor