¿Cómo puedo reemplazar una nueva línea (\ n) usando sed?


1371

¿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?


27
tres solo la herramienta adecuada para el trabajo si reemplaza un solo carácter por un solo carácter, mientras que el ejemplo anterior muestra reemplazar nueva línea con un espacio ... Entonces, en el ejemplo anterior, tr podría funcionar ... Pero sería más adelante limitante.
Enojado 84

99
tren la herramienta adecuada para el trabajo porque el interlocutor quería reemplazar cada nueva línea con un espacio, como se muestra en su ejemplo. El reemplazo de las nuevas líneas es excepcionalmente arcano, sedpero fácil de realizar tr. Esta es una pregunta común. La realización de reemplazos de expresiones regulares no se realiza trsino por sed, que sería la herramienta adecuada ... para una pregunta diferente.
Mike S

3
"tr" también puede simplemente eliminar la nueva línea `tr -d '\ n'` sin embargo, también puede eliminar los retornos para que sean más universales `tr -d '\ 012 \ 015' '.
anthony

2
ADVERTENCIA: "tr" actúa de manera diferente con respecto a un rango de caracteres entre Linux y máquinas Solaris más antiguas (EG sol5.8). Por ejemplo: `tr -d 'az' 'y` tr -d' [az] ''. Para eso te recomiendo que uses "sed" que no tiene esa diferencia.
anthony

2
@ Mike Gracias por la respuesta. Sigue tr '\012' ' 'con un echo. De lo contrario, también se elimina el último salto de línea en el archivo. tr '\012' ' ' < filename; echoHace el truco.
Bernie Reiter

Respuestas:


1514

Use esta solución con GNU sed:

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

Esto leerá todo el archivo en un bucle, luego reemplazará la (s) nueva (s) línea (s) con un espacio.

Explicación:

  1. Crea una etiqueta a través de :a.
  2. Agregue la línea actual y la siguiente al espacio del patrón a través de N.
  3. Si estamos antes de la última línea, bifurca a la etiqueta creada $!ba( $!significa no hacerlo en la última línea, ya que debería haber una nueva línea final).
  4. 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 con plataformas cruzadas 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 sedeste problema, que de otra manera sería simple, es problemático. Para una solución más simple y adecuada, vea esta respuesta .


45
@Arjan y Masi: OS X usa BSD en sedlugar de GNU sed, por lo que puede haber algunas diferencias sutiles (y algunas no tan sutiles) en los dos. Esto es un dolor constante si trabajas en máquinas con OS X y * nix. Por lo general, instalo GNU coreutilsy findutilsen OS X, e ignoro las versiones BSD.
Telémaco el

50
El :ano es un registro, es una etiqueta de sucursal. Es un objetivo para el bcomando * que funciona como "goto". Llamarlo registro implica que puede crear ubicaciones de almacenamiento. Solo hay dos "registros"; uno se llama "espacio de espera" que su script no está usando y el otro se llama "espacio de patrón". El Ncomando agrega una nueva línea y la siguiente línea del archivo de entrada al espacio del patrón. [* Puedes tener múltiples etiquetas y bcomandos. Si tiene un bcomando sin una etiqueta anexada, se bifurca hasta el final del script para leer la siguiente línea y volver a hacer un ciclo.]
pausa hasta nuevo aviso.

108
Puede ejecutar esta plataforma cruzada (es decir, en Mac OS X) ejecutando por separado los comandos en lugar de separarlos con punto y coma: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie

74
¿Por qué nadie está comentando sobre qué estúpido es esto? (No la respuesta en sí, sino el programa para el cual la respuesta propuesta es la mejor solución para un problema muy simple). Sed parece un automóvil que generalmente funciona bien, pero si desea conducir a una calle cercana específica, la única forma es levantar el automóvil con un helicóptero.
Ark-kun

12
Vamos amigos - 261 votos a favor de una solución loca e incomprensible que no funciona ???? sed es una excelente herramienta para suscripciones simples en una sola línea, para cualquier otra cosa simplemente use awk. Buen dolor ....
Ed Morton

1711

sedestá destinado a ser utilizado en la entrada basada en línea. Aunque puede hacer lo que necesitas.


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

tr '\n' ' ' < input_filename

o elimine 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

88
Sed está basado en líneas, por lo tanto, es difícil para él captar nuevas líneas.
Alexander Gladysh

191
sed funciona en un "flujo" de entrada, pero lo comprende en fragmentos delimitados por nueva línea. Es una herramienta Unix, lo que significa que hace una cosa muy bien. Lo único es "trabajar en un archivo en línea". Hacer que haga algo más será difícil y corre el riesgo de tener errores. La moraleja de la historia es: elige la herramienta adecuada. Una gran cantidad de sus preguntas parecen tomar la forma "¿Cómo puedo hacer que esta herramienta haga algo que nunca debió hacer?" Esas preguntas son interesantes, pero si surgen en el curso de la resolución de un problema real, probablemente lo esté haciendo mal.
dmckee --- ex gatito moderador

77
@JBBrown tres una joya que a menudo se pasa por alto para construir tuberías.
dmckee --- ex-gatito moderador

70
tr es genial, pero solo puedes reemplazar las nuevas líneas con caracteres individuales. Debe usar una herramienta diferente si desea reemplazar las nuevas líneas con una cadena
Eddy

21
@Eddy: solía tr para reemplazar nuevas líneas con un carácter que no aparecía en el texto (usé la tecla de retroceso), luego sed para reemplazar la tecla de retroceso con la cadena que quería usar
rjohnston

494

Respuesta rápida

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a crear una etiqueta 'a'
  2. N agrega la siguiente línea al espacio del patrón
  3. PS si no es la última línea , ba rama (ir a) etiqueta 'a'
  4. S sustituto , / \ n / regex 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 quepan en el espacio del patrón donde sed sustituirá a todos \ n caracteres


Alternativas

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

con golpe , lento

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

con perl , velocidad de sed

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

con tr , más rápido que sed , puede reemplazarse por un solo carácter

tr '\n' ' ' < file

con pegar , velocidad tr- como, puede reemplazar por un solo carácter

paste -s -d ' ' file

con awk , velocidad tr- like

awk 1 ORS=' ' file

Otra alternativa como "echo $ (<archivo)" es lenta, funciona solo en archivos pequeños y necesita procesar todo el archivo para comenzar el proceso.


Respuesta larga de sed FAQ 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 con \ n?

El \ n nunca coincidirá con la nueva línea al final de la línea porque la
nueva línea siempre se elimina antes de que la línea se coloque en el
espacio del patrón. Para obtener 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 de terminación, 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 stdout (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. Por lo tanto, los 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 en su lugar:

  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 que no sean GNU sed tienen límites para el tamaño del
búfer de patrón, 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, hay 3 opciones básicas:
(1) utilice el comando 'N' para agregar la línea Siguiente 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) use rangos de direcciones (consulte la sección 3.3, arriba)
para unir 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 específicas consecutivas?"). Este
ejemplo se puede modificar cambiando el comando de eliminación a otra
cosa, como 'p' (imprimir), 'i' (insertar), 'c' (cambiar), 'a' (agregar)
o 's' (sustituir) .

La opción (3) no colocará un \ n en el espacio del patrón, pero
coincide con un bloque de líneas consecutivas, por lo que es posible que ni
siquiera necesite el \ n para encontrar lo que está 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 '/ from here /, / to there / {...}' , es posible evitar el uso de \ n por completo.


66
trfue una gran idea, y su cobertura general lo convierte en una respuesta de alta calidad.
Nueva Alejandría

1
+1 por usar ( utilidad estándar ) paste... ¡y todos los demás!
Totor


44
La mejor parte de esta respuesta es que la "respuesta larga" explica exactamente cómo y por qué funciona el comando.
pdwalker

3
Esta puede ser la más útil de las miles de respuestas que he leído en stackexchange. Necesito unir varios caracteres a través de las líneas. Ningún ejemplo anterior de sed cubrió varias líneas y tr no puede manejar la coincidencia de múltiples caracteres. Perl se ve bien, pero no funciona como esperaba. Votaría esta respuesta varias veces si pudiera.
mightypile

225

Una alternativa awk más corta:

awk 1 ORS=' '

Explicación

Un programa awk está formado por reglas que consisten en bloques de código condicional, es decir:

condition { code-block }

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

Cuando awklee la entrada, la divide en registros en función del valor de RS(Separador de registros), que por defecto es una nueva línea, por awklo tanto , analizará la entrada en línea. La división también implica la eliminación RSdel registro de entrada.

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


55
Me gusta mucho esta solución simple, que es mucho más legible que otras
Fedir RYKHTIK

8
Si tiene más sentido, esto podría escribirse efectivamente como: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(agregando una nueva línea final solo para ilustrar inicio / fin); el "1" se evalúa para true(procesar la línea) y print(imprimir la línea). También se podría agregar un condicional a esta expresión, por ejemplo, solo trabajando en líneas que coinciden con un patrón: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
michael

2
Puede hacerlo más simple: codeawk 'ORS = ""' file.txtcode
Udi

Cuando se usa awk como este, desafortunadamente, la última línea de alimentación en el archivo también se elimina. Vea la respuesta anterior de Patrick Dark sobre el uso de 'tr' en una subshell como `cat file echo $ (tr "\ 012" "") `que hace el truco. Hábil.
Bernie Reiter

143

gnu sed tiene una opción -zpara registros separados por nulos (líneas). Solo puedes llamar:

sed -z 's/\n/ /g'

44
Incluso si la entrada contiene nulos, se conservarán (como delimitadores de registro).
Toby Speight

66
¿No cargará esto toda la entrada si no hay valores nulos? En este caso, el procesamiento de un archivo de varios gigabytes puede ser defectuoso.
Ruslan

3
@Ruslan, sí, carga toda la entrada. Esta solución no es una buena idea para archivos de varios gigabytes.
JJoao

77
Esta es seriamente la mejor respuesta. Las otras expresiones están demasiado retorcidas para recordar. @JJoao Puedes usarlo con -u, --unbuffered. El manmage dice: "cargar cantidades mínimas de datos de los archivos de entrada y vaciar las memorias intermedias de salida con mayor frecuencia".
not2qubit

entonces. mucho. esta.
sjas

85

La versión de Perl funciona de la manera que esperaba.

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

Como se señaló en los comentarios, vale la pena señalar que esto se edita en su lugar. -i.bakle dará una copia de seguridad del archivo original antes del reemplazo en caso de que su expresión regular no sea tan inteligente como pensaba.


23
Al menos, mencione que -isin un sufijo no se realiza una copia de seguridad . -i.baklo protege de un error fácil y feo (por ejemplo, olvidando escribir -py poner a cero el archivo).
Telémaco el

66
@Telemachus: Es un punto justo, pero se puede argumentar de cualquier manera. La razón principal por la que no lo mencioné es que el ejemplo sed en la pregunta del OP no hace copias de seguridad, por lo que parece superfluo aquí. La otra razón es que nunca he usado la funcionalidad de copia de seguridad (en realidad, las copias de seguridad automáticas son molestas), así que siempre olvido que está ahí. La tercera razón es que hace que mi línea de comando tenga cuatro caracteres más. Para bien o para mal (probablemente peor), soy un minimalista compulsivo; Solo prefiero la brevedad. Me doy cuenta de que no estás de acuerdo. Haré todo lo posible para recordar advertir sobre las copias de seguridad en el futuro.
ire_and_curses

66
@Ire_and_curses: En realidad, acabas de hacer un muy buen argumento para ignorarme. Es decir, tiene razones para sus elecciones, y si estoy o no de acuerdo con las opciones, ciertamente lo respeto. No estoy completamente seguro de por qué, pero últimamente he estado llorando por esto en particular (la -ibandera en Perl sin sufijo). Estoy seguro de que pronto encontraré algo más para obsesionarme. :)
Telemachus

Es realmente lamentable que esto no funcione con stdin al especificar el -nombre del archivo. ¿Hay una manera de hacerlo? Esa es mi manera de no preocuparme por modificar un archivo usando una tubería que comienza con cat.
Steven Lu

@StevenLu Perl leerá de STDIN de forma predeterminada si no se proporcionan nombres de archivo. Así que podría hacer, por ejemploperl -i -p -e 's/\n//' < infile > outfile
ire_and_curses

44

¿Quién necesita sed? Aquí está el bashcamino:

cat test.txt |  while read line; do echo -n "$line "; done

2
Voto a favor, normalmente usé la respuesta principal, pero cuando canalizo / dev / urandom a través de él, sed no se imprimirá hasta EOF, y ^ C no es EOF. Esta solución se imprime cada vez que ve una nueva línea. ¡Exactamente lo que necesitaba! ¡Gracias!
Vasiliy Sharapov

1
entonces por qué no: echo -n `cat days.txt` De esta publicación
Tony

99
@ Tony porque los backticks están en desuso y el gato es redundante ;-) Uso: echo $ (<days.txt)
seumasmac

10
Sin necesidad de utilizar cat: while read line; do echo -n "$line "; done < test.txt. Puede ser útil si un sub-shell es un problema.
Carlo Cannas

55
echo $(<file)exprime todos los espacios en blanco en un solo espacio, no solo las nuevas líneas: esto va más allá de lo que pide el OP.
Glenn Jackman

27

Para reemplazar todas las líneas nuevas con espacios usando awk, sin leer todo el archivo en la memoria:

awk '{printf "%s ", $0}' inputfile

Si quieres una nueva línea final:

awk '{printf "%s ", $0} END {printf "\n"}' inputfile

Puedes usar un personaje que no sea el espacio:

awk '{printf "%s|", $0} END {printf "\n"}' inputfile

END{ print ""}es una alternativa más corta para una nueva línea final.
Isaac

22
tr '\n' ' ' 

es el comando

Simple y fácil de usar.


14
o simplemente tr -d '\n'si no desea agregar un espacio
spuder

21

Tres cosas.

  1. tr(o cat, etc.) no es absolutamente necesario. (GNU) sedy (GNU) awk, cuando se combinan, pueden hacer el 99.9% de cualquier procesamiento de texto que necesite.

  2. stream! = basado en línea. edes un editor basado en líneas. sedno es. Vea la conferencia de sed para más información sobre la diferencia. La mayoría de las personas confunde sedestar basado en líneas porque, por defecto, no es muy codicioso en su coincidencia de patrones para coincidencias SIMPLES; por ejemplo, cuando realiza búsquedas y reemplazos de patrones por uno o dos caracteres, por defecto solo reemplaza en la primera coincidencia encuentra (a menos que el comando global especifique lo contrario). Ni siquiera habría un comando global si estuviera basado en líneas en lugar de en STREAM, porque solo evaluaría líneas a la vez. Intenta correr ed; notarás la diferencia. edes bastante útil si desea iterar sobre líneas específicas (como en un bucle for), pero la mayoría de las veces solo querrá sed.

  3. Habiendo dicho eso,

    sed -e '{:q;N;s/\n/ /g;t q}' file
    

    funciona bien en GNU sedversión 4.2.1. El comando anterior reemplazará todas las líneas nuevas con espacios. Es feo y un poco engorroso escribirlo, pero funciona bien. Los {}'s se pueden omitir, ya que solo se incluyen por razones de cordura.


3
Como una persona que solo sabe lo suficiente como sedpara hacer cosas básicas, debo decir que se trata más de lo que puede hacer, sedsino de lo fácil que es comprender lo que está sucediendo. Me cuesta mucho trabajar, sedasí que preferiría un comando más simple cuando pueda usarlo.
Nate

Usando t qcomo salto condicional, esto funciona con un patrón como s/\n / /(para unir todas las líneas que comienzan con un espacio) sin leer todo el archivo en la memoria. Práctico al transformar archivos de varios megabytes.
texthell

El artículo que ha vinculado no refleja lo que está diciendo
hek2mgl

Esto es casi 800 veces más lento que la respuesta aceptada en entradas grandes. Esto se debe a la ejecución de un sustituto para cada línea en entradas cada vez más grandes.
Thor

13

La respuesta con: una etiqueta ...

¿Cómo puedo reemplazar una nueva línea (\ n) usando sed?

... no funciona en freebsd 7.2 en la línea de comando:

(echo foo; barra de eco) | sed ': a; N; $! ba; s / \ n / / g'
sed: 1: ": a; N; $! ba; s / \ n / / g": etiqueta no utilizada 'a; N; $! ba; s / \ n / / g'
foo
bar

Pero si coloca el script sed en un archivo o usa -e para "compilar" el script sed ...

> (echo foo; barra de eco) | sed -e: a -e N -e '$! ba' -e 's / \ n / / g'
foo bar

o ...

> cat > x.sed << eof
:a
N
$!ba
s/\n/ /g
eof

> (echo foo; echo bar) | sed -f x.sed
foo bar

Quizás el sed en OS X es similar.


¡La serie de argumentos -e funcionó para mí en Windows usando MKS! ¡Gracias!
JamesG

12

Solución fácil de entender

Tuve este problema Lo sorprendente fue que necesitaba la solución para trabajar en BSD (Mac OS X) y GNU (Linux y Cygwin ) sedy tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Salida:

foo
bar
baz

(tiene una nueva línea al final)

Funciona en Linux, OS X y BSD , incluso sin soporte UTF-8 o con un terminal de mala calidad.

  1. Use trpara intercambiar la nueva línea con otro personaje.

    NULL( \000o \x00) es bueno porque no necesita soporte UTF-8 y no es probable que se use.

  2. Use sedpara hacer coincidir elNULL

  3. Úselo trpara intercambiar nuevas líneas adicionales si las necesita


1
Una nota sutil sobre la nomenclatura: el carácter \000se conoce comúnmente como NUL(una L), y NULLgeneralmente se usa cuando se habla de un puntero cero (en C / C ++).
semana de


9

No soy un experto, pero supongo sedque primero deberías agregar la siguiente línea al espacio del patrón, usando " N". De la sección "Espacio de patrones multilínea" en "Comandos avanzados de sed" del libro sed & awk (Dale Dougherty y Arnold Robbins; O'Reilly 1997; página 107 en la vista previa ):

El comando multilínea Siguiente (N) crea un espacio de patrón multilínea al leer una nueva línea de entrada y anexarlo al contenido del espacio de patrón. El contenido original del espacio del patrón y la nueva línea de entrada están separados por una nueva línea. El carácter de nueva línea incrustado puede coincidir en patrones mediante la secuencia de escape "\ n". En un espacio de patrón multilínea, el metacarácter "^" coincide con el primer carácter del espacio de patrón, y no con los caracteres que siguen a las nuevas líneas incrustadas. Del mismo modo, "$" coincide solo con la nueva línea final en el espacio del patrón, y no con ninguna nueva línea incrustada. Después de ejecutar el comando Siguiente, el control se pasa a los comandos posteriores en el script.

De man sed:

[2addr] N

Agregue la siguiente línea de entrada al espacio del patrón, utilizando un carácter de nueva línea incrustado para separar el material adjunto del contenido original. Tenga en cuenta que el número de línea actual cambia.

Lo he usado para buscar (múltiples) archivos de registro mal formateados, en los que la cadena de búsqueda se puede encontrar en la siguiente línea "huérfana".


7

Utilicé un enfoque híbrido para evitar la nueva línea usando tr para reemplazar las nuevas líneas con pestañas, luego reemplazando las pestañas con lo que quiera. En este caso, "
" ya que estoy tratando de generar saltos HTML.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`

6

En respuesta a la solución "tr" anterior, en Windows (probablemente usando la versión Gnuwin32 de tr), la solución propuesta:

tr '\n' ' ' < input

no funcionaba para mí, ya sea por error o en realidad reemplazaría el \ nw / '' por alguna razón.

Sin embargo, utilizando otra función de tr, la opción "eliminar" -d funcionó:

tr -d '\n' < input

o '\ r \ n' en lugar de '\ n'


3
En Windows, probablemente necesite usar tr "\n" " " < input. El shell de Windows (cmd.exe) no trata el apóstrofe como un carácter entre comillas.
Keith Thompson

No, en el subsistema de Windows 10 Ubuntu, debe usartr "\n\r" " " < input.txt > output.txt
user1491819

Esto funciona en Windows 10 utilizando GnuWin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. O, en lugar de Gnuwin32, use Gow (Gnu en Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt

5

Solución a prueba de balas. Binary-data-safe y compatible con POSIX, pero lento.

POSIX sed requiere entrada de acuerdo con el archivo de texto POSIX y las definiciones de línea POSIX , por lo que no se permiten bytes NULL y líneas demasiado largas y cada línea debe terminar con una nueva línea (incluida la última línea). Esto dificulta el uso de sed para procesar datos de entrada arbitrarios.

La siguiente solución evita sed y, en su lugar, convierte los bytes de entrada en códigos octales y luego nuevamente en bytes, pero intercepta el código octal 012 (nueva línea) y genera la cadena de reemplazo en su lugar. Por lo que puedo decir, la solución es compatible con POSIX, por lo que debería funcionar en una amplia variedad de plataformas.

od -A n -t o1 -v | tr ' \t' '\n\n' | grep . |
  while read x; do [ "0$x" -eq 012 ] && printf '<br>\n' || printf "\\$x"; done

Documentación de referencia POSIX: sh , lenguaje de comandos de shell , od , tr , grep , read , [ , printf .

Ambos read , [y printfestán integrados en al menos bash, pero eso probablemente no esté garantizado por POSIX, por lo que en algunas plataformas podría ser que cada byte de entrada inicie uno o más procesos nuevos, lo que ralentizará las cosas. Incluso en bash, esta solución solo alcanza unos 50 kB / s, por lo que no es adecuada para archivos grandes.

Probado en Ubuntu (bash, dash y busybox), FreeBSD y OpenBSD.


5

En algunas situaciones, tal vez pueda cambiar RSa otra cadena o carácter. De esta manera, \ n está disponible para sub / gsub:

$ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file

El poder de las secuencias de comandos de shell es que si no sabe cómo hacerlo de una manera, puede hacerlo de otra manera. Y muchas veces tiene más cosas que tener en cuenta que hacer una solución compleja en un problema simple.

En cuanto a que gawk es lento ... y lee el archivo en la memoria, no lo sé, pero para mí gawk parece funcionar con una línea a la vez y es muy muy rápido (no tan rápido como algunos de los otros). , pero el tiempo para escribir y probar también cuenta).

Proceso MB e incluso GB de datos, y el único límite que encontré es el tamaño de la línea.


5

Si tiene la mala suerte de tener que lidiar con las terminaciones de línea de Windows, debe eliminar el \ry el\n

tr '[\r\n]' ' ' < $input > $output

Esto reemplaza [con un espacio, y \rcon un espacio, y \ncon un espacio, y ]con un espacio. tr -d '\r\n' <fileeliminaría cualquiera \ro \ncaracteres, pero eso tampoco es lo que se pregunta. tr -d '\r' <fileeliminará todos los \rcaracteres (independientemente de si son adyacentes \n), lo que probablemente esté más cerca de ser útil y posiblemente corrija la necesidad del OP (aún suponiendo que trcomprenda esta notación de barra invertida).
tripleee

4

Podrías usar xargs- reemplazará\n con un espacio de forma predeterminada.

Sin embargo, tendría problemas si su entrada tiene algún caso de unterminated quote, por ejemplo, si los signos de comillas en una línea dada no coinciden.


xargs también maneja muy bien la última línea:
AAAfarmclub

4

Encuentra y reemplaza usando \ n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

Marcador

Se convierte

# Comentario de marcador

Marcador


4

¿Por qué no encontré una solución simple con awk?

awk '{printf $0}' file

printf imprimirá todas las líneas sin líneas nuevas, si desea separar las líneas originales con un espacio u otro:

awk '{printf $0 " "}' file

echo "1\n2\n3" | awk '{printf $0}'esto funciona para mi @ edi9999
Itachi

Tienes razón lo siento, olvidé el fen printf
edi9999

este fue el único enfoque que funcionó para mí dentro de git bash para windows
Platón

3

En Mac OS X (usando FreeBSD sed):

# replace each newline with a space
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta'
printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta


3

Usando Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"

2
No necesita escapar de las comillas y el signo de dólar si cambia las externas a comillas simples. La letra "o" generalmente se considera una mala elección como nombre de variable, ya que puede confundirse con el dígito "0". Tampoco necesita inicializar su variable, por defecto es una cadena nula. Sin embargo, si usted no quiere un espacio inicial adquirida: awk '{s = s sp $0; sp = " "} END {print s}'. Sin embargo, vea mi respuesta para una forma de usar awk sin leer todo el archivo en la memoria.
Pausado hasta nuevo aviso.

Por favor, mira la respuesta de Thor en su lugar. Es la manera más eficiente, fácil de leer y simplemente mejor por todos los medios a este enfoque en comparación (aunque esto sería trabajar)!
mschilli

Amigo, lo entiendo. No hay necesidad de frotarlo en mi cara :-) La respuesta de Thor está muy arriba en la página de todos modos (lo cual es correcto), entonces, ¿qué te importa?
kralyk

3

Una solución que me gusta especialmente es agregar todo el archivo en el espacio de espera y reemplazar todas las nuevas líneas al final del archivo:

$ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}'
foobar

Sin embargo, alguien me dijo que el espacio de espera puede ser finito en algunas implementaciones de sed.


1
el reemplazo con una cadena vacía en su respuesta oculta el hecho de que usar siempre H para agregar al espacio de espera significa que el espacio de espera comenzará con una nueva línea. Para evitar esto, debe usar1h;2,$H;${x;s/\n/x/g;p}
Jeff

3

Reemplace las nuevas líneas con cualquier cadena, y reemplace la última nueva línea también

Las trsoluciones puras solo pueden reemplazarse con un solo carácter, y las sedsoluciones puras no reemplazan la última línea nueva de la entrada. La siguiente solución soluciona estos problemas y parece ser segura para los datos binarios (incluso con un entorno local UTF-8):

printf '1\n2\n3\n' |
  sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/<br>/g;s/%a/@/g;s/%p/%/g'

Resultado:

1<br>2<br>3<br>

Esto es malo porque producirá una salida no deseada en cualquier entrada que contenga@
Steven Lu

@StevenLu: No, @en la entrada está bien. Se escapa %ay regresa nuevamente. Sin embargo, es posible que la solución no sea completamente compatible con POSIX (los bytes NULL no están permitidos, por lo que no son buenos para los datos binarios, y todas las líneas deben terminar con una nueva línea para que la trsalida no sea realmente válida).
Håkon A. Hjortland

Ah Veo que lo has arreglado. Un poco complicado para lo que debería ser una operación simple, pero un buen trabajo.
Steven Lu

3

Es sed que introduce las nuevas líneas después de la sustitución "normal". Primero, recorta el carácter de nueva línea, luego lo procesa de acuerdo con sus instrucciones, luego introduce una nueva línea.

Con sed , puede reemplazar "el final" de una línea (no el carácter de nueva línea) después de recortar, con una cadena de su elección, para cada línea de entrada; pero, sed generará diferentes líneas. Por ejemplo, suponga que desea reemplazar el "final de línea" con "===" (más general que un reemplazo con un solo espacio):

PROMPT~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
PROMPT~$

Para reemplazar el carácter de nueva línea con la cadena, puede, ineficientemente, usar tr , como se señaló anteriormente, para reemplazar los caracteres de nueva línea con un "carácter especial" y luego usar sed para reemplazar ese carácter especial con la cadena que desea .

Por ejemplo:

PROMPT~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===PROMPT~$

3

Puedes usar este método también

sed 'x;G;1!h;s/\n/ /g;$!d'

Explicación

x   - which is used to exchange the data from both space (pattern and hold).
G   - which is used to append the data from hold space to pattern space.
h   - which is used to copy the pattern space to hold space.
1!h - During first line won't copy pattern space to hold space due to \n is
      available in pattern space.
$!d - Clear the pattern space every time before getting next line until the
      last line.

Flujo:
cuando la primera línea se obtiene de la entrada, se realiza el intercambio, por lo que 1 va al espacio de espera y \ n llega al espacio de patrón, luego agrega el espacio de espera al espacio de patrón, y luego se realiza la sustitución y se elimina el espacio de patrón.
Durante el intercambio de la segunda línea, 2 va al espacio de retención y 1 llega al espacio de patrón, luego Gagrega el espacio de retención al espacio de patrón, luego hcopia el patrón y se realiza la sustitución y se elimina. Esta operación continúa hasta que se alcanza eof y luego imprime el resultado exacto.


Sin embargo, tenga en cuenta que los echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'resultados en XY.
Espeluznante

3

Otro método GNU sed , casi el mismo que la respuesta de Zsolt Botykai , pero utiliza sedel comando y( transliterar ) menos utilizado , que guarda un byte de código (el final g):

sed ':a;N;$!ba;y/\n/ /'

Uno esperaría yque corriera más rápido que s(quizás a trvelocidades 20 veces más rápidas), pero en GNU sed v4.2.2 y es aproximadamente un 4% más lento que s.


Versión BSD más portátil sed:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'

2
Con BSD sed yes aproximadamente un 15% más rápido. Vea esta respuesta para un ejemplo de trabajo.
Thor

Además, con BSD, los comandos sed deben terminar después de una etiqueta, por sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'lo que sería el camino a seguir.
ghoti
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.