Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm using awk '{ gsub(/BAR|WIBBLE/, "FOO"); print }' to replace text in data like:

SOMETHING [BAR, WIBBLE]
SOMETHING [BAR]

This gives the desired result of:

SOMETHING [FOO, FOO]
SOMETHING [FOO]

But now I've had to update the text that requires replacing to be something like:

awk '{ gsub(/BAR|WIBBLE|ME/, "FOO"); print }'

Which turns text like:

SOMETHING [ME, WIBBLE]

into:

SOFOOTHING [FOO, FOO]

How can I limit my replacement to just the text between the brackets (i.e. leave the SOMETHING alone)?

EDIT

I also need robustness across whatever text SOMETHING might be (e.g. SHE GAVE ME THAT shouldn't have ME replaced).

share|improve this question
add comment

4 Answers

up vote 2 down vote accepted

Must that be awk? Is much easier in other languages where the substitution's replacement part can be a function call. For example perl:

perl -pe 'sub c{$s=shift;$s=~s/BAR|WIBBLE|ME/FOO/g;$s}s/\[.*?\]/c$&/ge' 
share|improve this answer
    
Thanks! That did it. @choroba and @Guru word boundary would have been great too, but I want to be robust in what text the SOMETHING should be. I'll update the question to make that clearer. –  Chris Oct 24 '12 at 16:30
add comment

With GNU awk you can set RS to the contents of brackets and then do the replacement on RT (matched record separator):

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

output:

SHE GAVE ME THAT
SOMETHING [FOO, FOO, SOMMER]
share|improve this answer
    
+12. That RT trick is wicked! –  Stephane Chazelas Feb 1 '13 at 16:04
add comment

Awk lacks backreferences in regular expression replacements, so it can't easily do replacements in context. Sed can do it:

sed -e 's/\(\[[^]]*\)BAR/\1FOO/' 's/\(\[[^]]*\)ME/\1FOO/'

If your sed supports alternations in regexps:

sed -e 's/\(\[[^]]*\)\(BAR\|ME\)/\1FOO/'

This only handles a single replacement inside each bracket pair, even with the g suffix, because [^]]* matches the longest close-bracket-free sequence. To replace all of them, use an explicit loop; note that this only works if FOO isn't a substring of BAR or ME.

sed -e ': a' -e 's/\(\[[^]]*\)BAR/\1FOO/' -e 't a' \
             -e 's/\(\[[^]]*\)ME/\1FOO/' -e 't a'

If you need something more complicated, use perl.

share|improve this answer
add comment
awk '{ gsub(/\bBAR\b|\bWIBBLE\b|\bME\b/, "FOO"); print }'
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.