Exact word matching in sed
is tricky, especially if you want to write a portable solution, or if your definition of a "word" contains special characters other than _
(as in your situation). The best way I have found to do this is to consider all 4 cases where a word might appear in a line of input:
- At the beginning
- At the end
- At both the beginning and the end (occupying the entire line)
- In the middle somewhere
If your definition of a word is simply a sequence of non-whitespace characters, then the following solution should work for you (tested):
_s='[ ]' # contains a space and a literal tab character (CTRL-V + TAB)
input_string=`echo "$input_string" | sed \
-e "s|^$search_string\\($_s\\)|\\1|g" \
-e "s|\\($_s\\)$search_string$|\\1|g" \
-e "s|^$search_string$||g" \
-e "s|\\($_s\\)$search_string\\($_s\\)|\\1\\2|g"`
Note that I have chosen |
as the delimiter instead of #
. This is because #
can show up in file names (for example, Emacs auto-save files) while |
is reserved, at least on Linux. Also note that the output will contain the whitespace character(s) surrounding each instance of $search_string
. If you would rather omit the whitespace, you can use this instead (tested):
_s='[ ]' # contains a space and a literal tab character (CTRL-V + TAB)
input_string=`echo "$input_string" | sed \
-e "s|^$_s*$search_string$_s\\{1,\\}||g" \
-e "s|$_s\\{1,\\}$search_string$_s*$||g" \
-e "s|^$search_string$||g" \
-e "s|\\($_s\\)$search_string$_s\\{1,\\}|\\1|g"`
That last expression looks a little different, and for good reason -- you don't want to remove whitespace on both sides of $search_string
once you've gotten this far in processing the input line, because in doing so, you would remove whitespace between unmatched words on either side of $search_string
, which would smoosh them together.
Final notes:
- You might be able to get away with omitting some of the
g
modifiers in
the sed
expressions, but it doesn't hurt to leave them in.
- It probably goes without saying, but if your
$search_string
is a path,
it cannot contain any space.
input_string=echo blah
isn't legal (you need a command substitution like$( ... )
or backticks. Aside from that, I suspect the issue is that/
is a non-word character, so that there is no word boundary before it - do you get the desired result if you remove the initial\b
? FYI you may be able to do what you want more simply using shell parameter substitution. – steeldriver Dec 30 '16 at 14:29"...\b..."
the shell will already try to parse that as an escape sequence, so sed doesn't even see it. Do you mind trying if"...\\b..."
works better? – Ulrich Schwarz Dec 30 '16 at 14:46${input_string##$search_string }
? – steeldriver Dec 30 '16 at 15:11