replace - comando - so sed tobias




Como substituir vários padrões de uma só vez com sed? (5)

Suponha que eu tenha uma string 'abbc' e queira substituir:

  • ab -> bc
  • bc -> ab

Se eu tentar duas substituições, o resultado não é o que eu quero:

echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab

Então, qual comando sed eu posso usar para substituir como abaixo?

echo abbc | sed SED_COMMAND
bcab

EDIT : Na verdade, o texto pode ter mais de dois padrões e eu não sei quantos substituições vou precisar. Como houve uma resposta dizendo que o sed é um editor de fluxo e seus substitutos são avidamente, acho que precisarei usar uma linguagem de script para isso.


Aqui está um awk baseado em oogas sed

echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab

Aqui está uma variação da resposta do ooga que funciona para múltiplas pesquisas e substituição de pares sem ter que verificar como os valores podem ser reutilizados:

sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt

Aqui está um exemplo:

antes:

some text AB some more text "BC" and more text.

depois de:

some text BC some more text "CD" and more text.

Note que \b denota limites de palavras, que é o que impede o ________ de interferir na busca (estou usando o GNU sed 4.2.2 no Ubuntu). Se você não estiver usando uma pesquisa de limite de palavras, essa técnica poderá não funcionar.

Observe também que isso fornece os mesmos resultados que remover s/________//g e anexar && sed -i 's/________//g' path_to_your_files/*.txt ao final do comando, mas não requer a especificação do caminho duas vezes.

Uma variação geral disso seria usar \x0 ou _\x0_ no lugar de ________ se você souber que não aparecem nulos em seus arquivos, como sugerido .


Isso pode funcionar para você (GNU sed):

sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file

Isso usa uma tabela de consulta que é preparada e mantida no espaço de espera (HS) e, em seguida, anexada a cada linha. Um marcador único (neste caso, \n ) é prefixado no início da linha e usado como um método para percorrer a pesquisa ao longo do comprimento da linha. Quando o marcador atinge o final da linha, o processo é concluído e é impressa a tabela de consulta e os marcadores sendo descartados.

NB A tabela de consulta é preparada no início e um segundo marcador único (neste caso:) escolhido para não colidir com as seqüências de substituição.

Com alguns comentários:

sed -r '
  # initialize hold with :abbc:bcab
  1 {
    x
    s/^/:abbc:bcab/
    x
  }

  G        # append hold to patt (after a \n)

  s/^/\n/  # prepend a \n

  :a

  /\n\n/ {
    P      # print patt up to first \n
    d      # delete patt & start next cycle
  }

  s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/
  ta       # goto a if sub occurred

  s/\n(.)/\1\n/  # move one char past the first \n
  ta       # goto a if sub occurred
'

A tabela funciona assim:

   **   **   replacement
:abbc:bcab
 **   **     pattern

Talvez algo assim:

sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'

Substitua ~ por um caractere que você sabe que não estará na string.


sed é um editor de fluxo. Ele procura e substitui avidamente. A única maneira de fazer o que você pediu é usar um padrão de substituição intermediário e alterá-lo de volta no final.

echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'







sed