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/'