trabalhando - utilizando o sed no linux




Como posso substituir uma nova linha(\ n) usando sed? (20)

Solução fácil de entender

Eu tive esse problema. O kicker foi que eu precisava da solução para trabalhar no BSD (Mac OS X) e no GNU (Linux e Cygwin ) sed e tr :

$ echo 'foo
bar
baz


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

Saída:

foo
bar
baz

(tem nova linha)

Ele funciona no Linux, OS X e BSD - mesmo sem suporte a UTF-8 ou com um terminal de baixa qualidade.

  1. Use tr para trocar a nova linha por outro caractere.

    NULL ( \000 ou \x00 ) é bom porque não precisa de suporte a UTF-8 e provavelmente não será usado.

  2. Use sed para corresponder ao NULL

  3. Use tr para trocar novas linhas extras se você precisar delas

Como posso substituir uma nova linha ( \n ) usando o comando sed?

Eu tentei sem sucesso:

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

Como faço para corrigir isso?


Solução à prova de balas. Dados binários seguros e compatíveis com POSIX, mas lentos.

POSIX sed requer entrada de acordo com o arquivo de texto POSIX e definições de linha POSIX , portanto, bytes NULL e linhas muito longas não são permitidas e cada linha deve terminar com uma nova linha (incluindo a última linha). Isso dificulta o uso do sed para processar dados de entrada arbitrários.

A solução a seguir evita sed e, em vez disso, converte os bytes de entrada em códigos octal e, em seguida, em bytes novamente, mas intercepta o código octal 012 (nova linha) e gera a string de substituição no lugar dela. Tanto quanto eu posso dizer a solução é compatível com POSIX, por isso deve funcionar em uma ampla variedade 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

Documentação de referência POSIX: sh , linguagem de comando shell , od , tr , grep , read , [ , printf .

Ambos read , [ e printf são built-ins em pelo menos bash, mas isso provavelmente não é garantido pelo POSIX, então em algumas plataformas pode ser que cada byte de entrada inicie um ou mais novos processos, o que retardará as coisas. Mesmo no bash, essa solução atinge apenas cerca de 50 kB / s, portanto, não é adequada para arquivos grandes.

Testado no Ubuntu (bash, dash e busybox), FreeBSD e OpenBSD.


É sed que introduz as novas linhas após a substituição "normal". Primeiro, ele corta o novo caractere de linha, depois ele processa de acordo com suas instruções e, em seguida, introduz uma nova linha.

Usando sed você pode substituir "o fim" de uma linha (não o caractere de nova linha) depois de ser aparada, com uma string de sua escolha, para cada linha de entrada; mas o sed produzirá linhas diferentes. Por exemplo, suponha que você queira substituir o "fim de linha" por "===" (mais geral do que a substituição por um único espaço):

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

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

Para substituir o novo caractere de linha pela cadeia de caracteres, você pode, ineficientemente, usar tr , como apontado anteriormente, para substituir os caracteres de nova linha por um "caractere especial" e usar sed para substituir esse caractere especial pela string desejada .

Por exemplo:

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~$

A resposta com o: um rótulo ...

Como posso substituir uma nova linha (\ n) usando sed?

... não funciona no freebsd 7.2 na linha de comando:

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'
foo
bar

Mas se você colocar o script sed em um arquivo ou usar -e para "construir" o script sed ...

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

ou ...

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

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

Talvez o sed no OS X seja semelhante.


Em algumas situações, talvez você possa alterar o RS para alguma outra string ou caractere. Dessa forma, \ n está disponível para sub / gsub:

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

O poder do script de shell é que, se você não souber como fazê-lo de uma maneira, poderá fazê-lo de outra maneira. E muitas vezes você tem mais coisas para levar em conta do que fazer uma solução complexa em um problema simples.

Em relação a coisa que gawk é lenta ... e lê o arquivo na memória, eu não sei disso, mas para mim o gawk parece trabalhar com uma linha na hora e é muito muito rápido (não tão rápido quanto alguns dos outros) , mas o tempo para escrever e testar também conta).

Eu processo MB e até GB de dados, e o único limite que encontrei é o tamanho da linha.


Em resposta à solução "tr" acima, no Windows (provavelmente usando a versão Gnuwin32 do tr), a solução proposta:

tr '\n' ' ' < input

não estava funcionando para mim, seria erro ou realmente substituir o \ nw / '' por algum motivo.

Usando outro recurso do tr, a opção "delete" -d funcionou:

tr -d '\n' < input

ou '\ r \ n' em vez de '\ n'


Eu usei uma abordagem híbrida para contornar a coisa newline usando tr para substituir novas linhas com guias, em seguida, substituindo guias com o que eu quiser. Nesse caso, "
"desde que eu estou tentando gerar quebras de HTML.

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

No 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

Para remover linhas vazias:

sed -n "s/^$//;t;p;"

Para substituir todas as novas linhas por espaços usando o awk, sem ler todo o arquivo na memória:

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

Se você quiser uma nova linha final:

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

Você pode usar um caractere diferente de espaço:

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

Três coisas.

  1. tr (ou cat , etc.) não é absolutamente necessário. (GNU) sed e (GNU) awk , quando combinados, podem fazer 99,9% de qualquer processamento de texto que você precisa.

  2. stream! = baseado em linha. ed é um editor baseado em linhas. sed não é. Veja a palestra para mais informações sobre a diferença. A maioria das pessoas confunde que o sed é baseado em linhas porque, por padrão, ele não é muito ganancioso na correspondência de padrões para correspondências SIMPLE - por exemplo, ao fazer pesquisa de padrão e substituir por um ou dois caracteres, ele substitui por padrão apenas o primeiro. correspondência que encontra (a menos que especificado de outra forma pelo comando global). Não haveria nem mesmo um comando global se fosse baseado em linhas em vez de baseado em STREAM, porque ele avaliaria apenas linhas de cada vez. Tente executar o ed ; Você notará a diferença. ed é bastante útil se você quiser iterar sobre linhas específicas (como em um loop for), mas na maioria das vezes você só quer sed .

  3. Dito isto,

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

    funciona muito bem no GNU sed versão 4.2.1. O comando acima substituirá todas as novas linhas por espaços. É feio e um pouco difícil de digitar, mas funciona muito bem. Os {} podem ser deixados de fora, pois só estão incluídos por motivos de sanidade.


Uma alternativa awk mais curta:

awk 1 ORS=' '

Explicação

Um programa awk é formado por regras que consistem em blocos de código condicionais, ou seja:

condition { code-block }

Se o bloco de códigos for omitido, o padrão será usado: { print $0 } . Assim, o 1 é interpretado como uma condição verdadeira e a print $0 é executada para cada linha.

Quando awk lê a entrada, ela é dividida em registros baseados no valor de RS (Record Separator), que por padrão é uma nova linha, portanto, o awk por padrão analisará a entrada line-wise. A divisão também envolve retirar o RS do registro de entrada.

Agora, ao imprimir um registro, o ORS (Output Record Separator) é anexado a ele, o padrão é novamente uma nova linha. Então, alterando o ORS para um espaço, todas as novas linhas são alteradas para espaços.


Usando Awk:

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

Use tr vez disso?

tr '\n' ' ' < input_filename

ou remova os caracteres de nova linha inteiramente:

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

ou se você tiver a versão GNU (com suas opções longas)

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

Você pode usar xargs :

seq 10 | xargs

ou

seq 10 | xargs echo -n

Você poderia usar xargs - ele substituirá \n por um espaço por padrão.

No entanto, teria problemas se sua entrada tivesse qualquer caso de uma unterminated quote , por exemplo, se os sinais de cotação em uma determinada linha não coincidem.


@OP, se você quiser substituir novas linhas em um arquivo, você pode usar dos2unix (ou unix2dox)

dos2unix yourfile yourfile

Você pode usar esse método também

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

Explicação

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.

Fluxo:
Quando a primeira linha sai da entrada, a troca é feita, então 1 vai para manter espaço e \ n chega ao espaço padrão, então anexando o espaço de espera ao espaço padrão, e então a substituição é executada e excluída do espaço padrão.
Durante a segunda troca de linha é feita, 2 vai para manter espaço e 1 chega ao espaço padrão, em seguida, Ganexa o espaço de armazenamento no espaço padrão, hcopia o padrão para ele e a substituição é feita e excluída. Esta operação é continuada até que seja alcançado o eof e, em seguida, imprimir o resultado exato.


Outro método GNU sed , quase o mesmo que a resposta de Zsolt Botykai , mas este usa sedo comando menos usado y( transliterado ), que salva um byte de código (o trailing g):

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

Espera-se que yele corra mais rápido que s(talvez a trvelocidades 20x mais rápido), mas no GNU sed v4.2.2 y é cerca de 4% mais lento que s.

Versão BSD mais portátil sed:

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

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

Isso não funciona para arquivos grandes (limite de buffer), mas é muito eficiente se houver memória suficiente para armazenar o arquivo. (Correção H-> 1h;1!Hapós a boa observação de @hilojack)

Outra versão que altera a nova linha durante a leitura (mais cpu, menos memória)

 sed ':loop
 $! N
 s/\n/ /
 t loop' YourFile