Skip to content

Instantly share code, notes, and snippets.

@jcamenisch
Created January 24, 2012 19:19
Show Gist options
  • Save jcamenisch/1671995 to your computer and use it in GitHub Desktop.
Save jcamenisch/1671995 to your computer and use it in GitHub Desktop.
Lightning-fast project-wide find/replace with git grep and sed
gg_replace() {
if [[ "$#" == "0" ]]; then
echo 'Usage:'
echo ' gg_replace term replacement file_mask'
echo
echo 'Example:'
echo ' gg_replace cappuchino cappuccino *.html'
echo
else
find=$1; shift
replace=$1; shift
ORIG_GLOBIGNORE=$GLOBIGNORE
GLOBIGNORE=*.*
if [[ "$#" = "0" ]]; then
set -- ' ' $@
fi
while [[ "$#" -gt "0" ]]; do
for file in `git grep -l $find -- $1`; do
sed -e "s/$find/$replace/g" -i'' $file
done
shift
done
GLOBIGNORE=$ORIG_GLOBIGNORE
fi
}
gg_dasherize() {
gg_replace $1 `echo $1 | sed -e 's/_/-/g'` $2
}
@glyph
Copy link

glyph commented Oct 16, 2020

Here's my version: https://gist.github.com/glyph/9beafa8a7b26e5ca9f6666448fa5810d

gg_replace() {
    if [[ "$#" -lt "2" ]]; then
        echo "
Usage:
  $0 term replacement file_mask
Example:
  $0 cappuchino cappuccino '*.html'
";
    else
        local find="$1"; shift;
        local replace="$1"; shift;
        git grep -zlI "${find}" -- "$@" |
            xargs -0 sed -e "s/${find}/${replace}/g" -i '' ;
    fi;
}

A few notes:

  • passes shellcheck
  • doesn't depend on word splitting so doesn't need to monkey with GLOBIGNORE
  • supports spaces, newlines, and (apropos of dawalama's version ;-)) ~~~~~ in path names
  • it still has the problem described in dwheeler's https://dwheeler.com/essays/filenames-in-shell.html section 3.3, since I couldn't figure out a quick way to make git grep prefix all its output with ./
  • it's a bit faster since it doesn't spawn new sed processes quite so many times

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment