I always forget how to do this efficiently with Vim's arglist. Drawing inspiration from a post over at Stack Overflow, I wrote a Bash function to perform a project-wide search & replace.
It does the following:
- find files matching a file-pattern
- narrow down to those files containing a search-pattern
- within those files, replace all occurrences of the search-pattern
Example usage: greplace **.rb old_method new_method
greplace() {
if [ "${#}" != 3 ]; then
echo "Usage: greplace file_pattern search_pattern replacement"
return 1
else
file_pattern=$1
search_pattern=$2
replacement=$3
find . -name "${file_pattern}" |
xargs grep -rwl "${search_pattern}" |
xargs sed -i '' "s/[[:<:]]${search_pattern}[[:>:]]/${replacement}/g"
fi
}
I'm on OSX, so unfortunately I had to use the ugly (and I assume non-portable) [[:<:]]
word-boundaries for sed
. I tried \b
and \<
, with and without -E
(for extended regular expressions), but still no dice.
I also debated whether to bake the word-boundaries in or leave them up to the caller (my poor little fingers). But I can't imagine wanting use this without word boundaries. I'd much rather miss a replacement because it's a variation on the search term than accidentally mangle a word happens to contain the search term.
Another potential issue is the fact that I'm using sed -i ''
to perform the in-place replacements without making any backup files. This seems fine for my use, since I'm invariably using Git for version control. I'm curious how big a risk this is though.
Update Props to janos for his pointers and improvements. Here's an updated version:
greplace() {
if [ "$#" != 3 ]; then
echo "Usage: greplace file_pattern search_pattern replacement"
return 1
else
file_pattern=$1
search_pattern=$2
replacement=$3
# This works with BSD grep and the sed bundled with OS X.
# GNU grep takes `-Z` instead of `--null`.
# Other versions of sed may not support the `-i ''` syntax.
find . -name "$file_pattern" -exec grep -lw --null "$search_pattern" {} + |
xargs -0 sed -i '' "s/[[:<:]]$search_pattern[[:>:]]/$replacement/g"
fi
}