Deve ser awk
? É muito mais fácil em outros idiomas onde a peça de substituição da substituição pode ser uma chamada de função. Por exemplo perl
:
perl -pe 'sub c{$s=shift;$s=~s/BAR|WIBBLE|ME/FOO/g;$s}s/\[.*?\]/c$&/ge'
Estou usando awk '{ gsub(/BAR|WIBBLE/, "FOO"); print }'
para substituir texto em dados como:
SOMETHING [BAR, WIBBLE]
SOMETHING [BAR]
Isso dá o resultado desejado de:
SOMETHING [FOO, FOO]
SOMETHING [FOO]
Mas agora eu tive que atualizar o texto que requer substituição para ser algo como:
awk '{ gsub(/BAR|WIBBLE|ME/, "FOO"); print }'
Que transforma texto como:
SOMETHING [ME, WIBBLE]
para:
SOFOOTHING [FOO, FOO]
Como posso limitar minha substituição apenas ao texto entre colchetes (ou seja, deixar o SOMETHING
sozinho)?
EDITAR
Também preciso de robustez em qualquer texto SOMETHING
(por exemplo, SHE GAVE ME THAT
não deveria ter ME
substituído).
Com o GNU awk, você pode definir RS
para o conteúdo dos colchetes e, em seguida, fazer a substituição no RT
(separador de registros correspondente):
awk -v RS='\[[^]]*\]' '{ gsub(/\<(BAR|WIBBLE|ME)\>/, "FOO", RT); printf "%s%s", $0, RT }' infile
infile:
cat << EOF > infile
SHE GAVE ME THAT
SOMETHING [ME, WIBBLE, SOMMER]
EOF
saída:
SHE GAVE ME THAT
SOMETHING [FOO, FOO, SOMMER]
O awk não tem referências anteriores nas substituições de expressões regulares, por isso não é fácil fazer substituições no contexto. Sed pode fazer isso:
sed -e 's/\(\[[^]]*\)BAR/FOO/' 's/\(\[[^]]*\)ME/FOO/'
Se o seu sed suportar alternações em regexps:
sed -e 's/\(\[[^]]*\)\(BAR\|ME\)/FOO/'
Isso lida apenas com uma única substituição dentro de cada par de colchetes, mesmo com o sufixo g
, porque [^]]*
corresponde à sequência mais longa sem parentesco. Para substituir todos eles, use um loop explícito; Observe que isso só funciona se FOO
não for uma subseqüência de BAR
ou ME
.
sed -e ': a' -e 's/\(\[[^]]*\)BAR/FOO/' -e 't a' \
-e 's/\(\[[^]]*\)ME/FOO/' -e 't a'
Se você precisar de algo mais complicado, use perl .
awk '{ gsub(/\bBAR\b|\bWIBBLE\b|\bME\b/, "FOO"); print }'