sed whole word search and replace

Viewed 128228

How do I search and replace whole words using sed?

Doing

sed -i 's/[oldtext]/[newtext]/g' <file> 

will also replace partial matches of [oldtext] which I don't want it to do.

5 Answers

\b in regular expressions match word boundaries (i.e. the location between the first word character and non-word character):

$ echo "bar embarassment" | sed "s/\bbar\b/no bar/g"
no bar embarassment

Use \b for word boundaries:

sed -i 's/\boldtext\b/newtext/g' <file>

In one of my machine, delimiting the word with "\b" (without the quotes) did not work. The solution was to use "\<" for starting delimiter and "\>" for ending delimiter.

To explain with Joakim Lundberg's example:

$ echo "bar embarassment" | sed "s/\<bar\>/no bar/g"
no bar embarassment

For a posix compliant alternative, consider replacing word boundary matches (\b) by an expanded equivalent ([^a-zA-Z0-9]), also taking into account occurrences at start of line (^) and end of line ($).

However, this quickly becomes impractical if you want to support repeated occurrences of the word to replace (e.g. oldtext oldtext). sed --posix doesn't recognize expressions such as \(^\|[^a-zA-Z0-9]\), and you can't make use of lookarounds.

It seems we have to explictly match all possible cases. Here's a solution to replace mint with minty:

echo 'mint 0mint mint mint0 mint__mint mint__ mint_ -mint mint mint mint_ mint -mint- mint mint mintmint mint' \
  | sed --posix '   
s/^mint$/minty/g;
s/^mint\([^a-zA-Z0-9]\)/minty\1/g;
s/\([^a-zA-Z0-9]\)mint$/\1minty/g;
s/\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)/\1minty\2minty\3minty\4/g;
s/\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)/\1minty\2minty\3/g;
s/\([^a-zA-Z0-9]\)mint\([^a-zA-Z0-9]\)/\1minty\2/g;
'
# minty 0mint minty mint0 minty__minty minty__ minty_ -minty minty minty minty_ minty -minty- minty minty mintmint minty
Related