Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Bulk search & replace with ag (the_silver_searcher)
# ag <https://github.com/ggreer/the_silver_searcher>
# usage: ag-replace.sh [search] [replace]
# caveats: will choke if either arguments contain a forward slash
# notes: will back up changed files to *.bak files
ag -0 -l $1 | xargs -0 perl -pi.bak -e "s/$1/$2/g"
# or if you prefer sed's regex syntax:
ag -0 -l $1 | xargs -0 sed -ri.bak -e "s/$1/$2/g"
@dennislysenko

This comment has been minimized.

Copy link

@dennislysenko dennislysenko commented Sep 29, 2016

If you add -0 right after xargs, it can also handle files with spaces in the filename ;)

@graingert

This comment has been minimized.

Copy link

@graingert graingert commented May 5, 2017

@dennislysenko you need the -0 in both ag and xargs

ag -0 -l $1 | xargs -0 sed -ri.bak -e "s/$1/$2/g"
@aaronmswan

This comment has been minimized.

Copy link

@aaronmswan aaronmswan commented May 2, 2018

For what it's worth, this can be added as a function to .bashrc as

function agr { ag -0 -l "$1" | xargs -0 perl -pi.bak -e "s/$1/$2/g"; }
export -f agr
@KevOrr

This comment has been minimized.

Copy link

@KevOrr KevOrr commented May 3, 2018

Even better so you don't have to worry about slashes:

function agr { ag -0 -l "$1" | AGR_FROM="$1" AGR_TO="$2" xargs -r0 perl -pi -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'; }

There could be some incompatibilities between the two regex languages though.

@ixis-kyle

This comment has been minimized.

Copy link

@ixis-kyle ixis-kyle commented May 2, 2019

@KevOrr,
function agr { ag -0 -l "$1" | AGR_FROM="$1" AGR_TO="$2" xargs -r0 perl -pi -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'; } has typo. Should be:
function agr { ag -0 -l "$1" | AGR_FROM="$1" AGR_TO="$2" xargs -0 perl -pi -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'; }.

at least thats what worked for me, I honestly dont know much about the -0 argument.

@NightMachinary

This comment has been minimized.

Copy link

@NightMachinary NightMachinary commented Jul 29, 2019

@ixis-kyle It’s correct, and necessary:

-r, --no-run-if-empty
              If  the  standard input does not contain any nonblanks,
              do not run the command.  Normally, the command  is  run
              once  even  if there is no input.  This option is a GNU
              extension.
@NightMachinary

This comment has been minimized.

Copy link

@NightMachinary NightMachinary commented Jul 29, 2019

(See latest version https://gist.github.com/NightMachinary/719ec06299c65b5216d551658b78c951)

comment() { 
}
doc() { 
}
function agr { 
doc 'usage: from=sth to=another agr [ag-args]'
comment -l --files-with-matches

ag -0 -l "$from" "${@}" | pre-files "$from" "$to"
}
pre-files() {
doc 'stdin should be null-separated list of files that need replacement; $1 the string to replace, $2 the replacement.'
comment '-i backs up original input files with the supplied extension (leave empty for no backup; needed for in-place replacement.)(do not put whitespace between -i and its arg.)'
comment '-r, --no-run-if-empty
              If  the  standard input does not contain any nonblanks,
              do not run the command.  Normally, the command  is  run
              once  even  if there is no input.  This option is a GNU
              extension.'

AGR_FROM="$1" AGR_TO="$2" xargs -r0 perl -pi.pbak -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'
}

You can use it like this:

from=str1 to=sth agr path1 path2 ...

Supply no paths to make it use the current directory.
Note that ag, xargs, and perl need to be installed and on PATH.

@nikisix

This comment has been minimized.

Copy link

@nikisix nikisix commented Apr 17, 2020

I had to use ag's --nocolor argument for it go work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.