I thought that with the following code, doing something like git_grep_sed -w pattern replacement
would match whole words. However, if say, the match is if
, it will also match the substring in fifa
. It seems like the sed
part isn't actually listening to the -w
flag.
git_grep_sed() {
local grep_options=()
local search_pattern
local replacement
while [[ $1 =~ ^- ]]; do
grep_options+=("$1")
shift
done
search_pattern=$1
replacement=$2
git grep -l "${grep_options[@]}" "$search_pattern" | xargs sed -i "s/$search_pattern/$replacement/g"
}
Why is this, and how to fix it? Maybe I have to use something else instead of sed?
Because you didn't give sed
any flags. And in fact there aren't any that would help. Let's say you have a file like
if consistency == "stiff":
add_water()
git grep -w
will recognise the first line, as it does contain the word if
by itself, but sed
will just happily change all if
instances, because it is unconstrained.
You need to add word boundary anchors to sed
pattern. Unfortunately, it is not as easy as it seems, because different versions of sed
do it differently.
unset use_osx_sed
if sed -e 's/[[:<:]]//' <<<"" >/dev/null 2>&1
then
use_osx_sed=1
fi
git_grep_sed() {
local grep_options=()
local search_pattern
local sed_search_pattern
local replacement
local full_word
while [[ $1 =~ ^- ]]; do
grep_options+=("$1")
if [[ "$1" == -w ]]
then
full_word=1
fi
shift
done
search_pattern="$1"
sed_search_pattern="$1"
replacement="$2"
if [[ -n "$full_word" ]]
then
if [[ -n "$use_osx_sed" ]]
then
sed_search_pattern="[[:<:]]$search_pattern[[:>:]]"
else
sed_search_pattern="\\<$search_pattern\\>"
fi
fi
git grep -l "${grep_options[@]}" "$search_pattern" | xargs sed -i "s/$sed_search_pattern/$replacement/g"
}
(The name is probably not accurate. Maybe non_gnu_sed
? I don't know how far this reaches, I can only test on OSX and Linux...)