¿Cómo puedo reemplazar cada nueva línea (\n) con un espacio usando sed?
¿Cómo puedo reemplazar una nueva línea (" \n
") con un espacio (" ") usando el
sed
comando?
Intenté sin éxito:
sed 's#\n# #g' file
sed 's#^$# #g' file
¿Cómo lo soluciono?
sed
está diseñado para usarse en entradas basadas en líneas. Aunque puede hacer lo que necesitas.
Una mejor opción aquí es usar el tr
comando 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:
sed
comienza leyendo la primera línea excluyendo la nueva línea en el espacio del patrón.- Crea una etiqueta mediante
:a
. - Agregue una nueva línea y la siguiente línea al espacio del patrón mediante
N
. - 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 ejecutarN
nuevamente, lo que terminaría el script si no hay más entradas). - 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 sed
para 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 .
Respuesta rápida
sed ':a;N;$!ba;s/\n/ /g' file
- :a crea una etiqueta 'a'
- N agregue la siguiente línea al espacio del patrón
- ps si no es la última línea , rama ba (ir a) etiqueta 'a'
- 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.
GNU sed tiene una opción, -z
para registros (líneas) separados por nulos. Puedes simplemente llamar:
sed -z 's/\n/ /g'
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 1
interpreta como una condición verdadera y print $0
se ejecuta para cada línea.
Cuando awk
lee 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 awk
analizará la entrada de forma predeterminada. La división también implica eliminar RS
el registro de entrada.
Ahora, al imprimir un registro, ORS
se le agrega (Separador de registros de salida), el valor predeterminado es nuevamente una nueva línea. Entonces, al cambiar ORS
a un espacio, todas las nuevas líneas se convierten en espacios.