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 have a list of replacements like so:

search_and -> replace
big_boy -> bb
little_boy -> lb
good_dog -> gd
...

I need to make replacements for the above, but at the same time avoid matching strings that are longer like these:

big_boys
good_little_boy

I tried this:

sed -i -r "s/$(\W){search}(\W)/$\1{replacement}\2/g"

But the above does not work when the string ("good_dog" in this case) occurs at the end of a line like so:

Mary had a 'little_boy', good_little_boy, $big_boy, big_boys and good_dog

Mary had a 'lb', good_little_boy, $bb, big_boys and good_dog

And I doubt the above would work when the string occurs at the start of the line too. Is there a good way to do the search and replacement?

share|improve this question

3 Answers 3

up vote 4 down vote accepted

If you're using GNU sed (which bare -i suggests you are), there is a "word boundary" escape \b:

sed -i "s/\b$SEARCH\b/$REPLACE/g"

\b matches exactly on a word boundary: the character to one side is a "word" character, and the character to the other is not. It is a zero-width match, so you don't need to use capturing subgroups to keep the value with \1 and \2. There is also \B, which is exactly the opposite.


If you're not using GNU sed, you can use alternation with the start and end of line in your capturing subpatterns: (\W|^). That will match either a non-word character or the start of a line, and (\W|$) will match either a non-word character or the end of a line. In that case you still use \1 and \2 as you were. Some non-GNU seds do support \b anyway, at least in an extended mode, so it's worth giving that a try regardless.

share|improve this answer
    
That's awesome! Thanks for the quick response :) –  Question Overflow Jul 12 at 8:54
1  
@Michael Homer: What sed version support \b except GNU sed? –  Gnouc Jul 12 at 9:32
    
I was thinking mostly of Busybox's sed, I think, but of course that's GNU-based anyway. –  Michael Homer Jul 12 at 22:44

If you want more portable, you can use \< and \>:

sed -i "s/\<$SEARCH\>/$REPLACE/g" file

\< and \> work in gsed, ssed, sed15, sed16, sedmod.

\b and \B work in gsed only.

In Mac OSX, you must use this syntax:

sed -i '' -e "/[[:<:]]$SEARCH[[:>:]]/$REPLACE/g" file
share|improve this answer

You could also use perl, which should support \b on all platforms. Assuming your list of replacements is in the format you show (separated by ->), you could do:

perl -F"->" -ane 'chomp;$rep{$F[0]}=${$F[1]}; 
                  END{open(A,"file"); 
                    while(<A>){
                        s/\b$_\b/$rep{$_}/g for keys(%rep); 
                        print
                    }
                  }' replacements

Explanation

  • The -a makes perl run like awk, automatically splitting fields into the array @F so $F[0] is the 1st field, $F[1] the second etc. The -F sets the input field separator, just like -F in awk. The -n means "read the input file, line by line and apply the script given by -e to each line".

  • chomp : removes newlines (\n) from the end of the line.

  • $rep{$F[0]}=${$F[1]}; : this populates the hash %rep making the pattern to be replaced (the first field, $F[0]) the key and the replacement ($F[1]) the value. *END{} : this is executed after the input file (replacements) has been read.
  • open(A,"file") : open the file file for reading with filehandle A.
  • while (<A>) : read the file line by line.
  • s/// for keys(%rep) : this will iterate through all the keys of the %rep hash, saving each key as the special variable $_. The s/// is the substitution operator and is making the same substitution as explained in Michael's answer.

You could also read through the file and use sed as shown in the other answers:

$ sed 's/->/\t/' replacements | 
    while IFS=$'\t' read from to; do sed -i "s/\b$from\b/$to/g" file; done
share|improve this answer

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.