ChatGPT解决这个技术问题 Extra ChatGPT

sed whole word search and replace

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.


J
Joakim Lundborg

\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

@OlegMazko I also came looking for the posix acceptable method to use in vim and what worked for me was s/\<7//g. I was trying to remove a 7 at the start of a word in my code. This link, specifically, J-P's solution, led me to the answer: stackoverflow.com/questions/3864467/… (couldn't get markdown to embed it like yours for some reason).
Thank you I was going mad trying to do a replacement on the word "and" so \band\b saved the day :)
Would be using [[:space:]]word[[:space:]] be considered acceptable @jimh
Didn't work for me. Maybe a different build of sed? Was default on CentOS 7
R
Roland Weber

On Mac OS X, neither of these regex syntaxes work inside sed for matching whole words

\bmyWord\b

\

Hear me now and believe me later, this ugly syntax is what you need to use:

/[[:<:]]myWord[[:>:]]/

So, for example, to replace mint with minty for whole words only:

sed "s/[[:<:]]mint[[:>:]]/minty/g"

Source: re_format man page


Just install GNU sed (and every other GNU tool) via MacPorts or Homebrew and make sure it comes first in your PATH. It's possible to make a Mac fairly usable.
@JimStewart great way to break a bunch of tools that assume ‘when on OS X, do as the OS Xers.’ That said, I can definitely suggest brew install coreutils, which prefixes all of the gnu tools.
brew install gnu-sed to use gsed
answered my own question. there's a list of packages @ apple.stackexchange.com/questions/69223/…
Using perl is always a better solution: perl -pe 's|\bone\b|two|g'. Works stably while sed fails here and there.
t
t0r0X

Use \b for word boundaries:

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

Be careful with the []: o,l --> [newtext],[newtext]. You obviously meant sed -i 's/\boldtext\b/newtext/g'
C
Community

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

f
fzbd

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