As pointed out in randomir's comment and the question he links to, you have to use double quotes so variables are expanded:
old="oldtext"
new="newtext"
grep -rZli "$old" | xargs -0 sed -i "s/$old/$new/gi"
I changed a few other things as well:
- Lowercase variable names to avoid clashes with names reserved for environment variables
- grep
-Z
option to separate filenames with a NUL byte to deal with special characters such as newlines in filenames
- Skipped
*
after the sed pattern, as it defaults to the working directory anyway
-0
option for xargs to expect NUL byte separated filenames
- Skipped the (deprecated)
-i
option as the filenames go to the end of the command anyway
i
flag for the substitution to match the case insensitive matching in the grep command
Some of these require GNU grep, xargs and sed.
If you don't look at a huge number of files to justify grepping them first, you can just run a single sed process over them all, using a generalized **/*
glob:
shopt -s globstar
sed -i "s/$old/$new/gi" **/*
This will complain about sed trying to run on directories, but it doesn't hurt; if all your files have a common extension like .txt
, you could use **/*.txt
to avoid that.
If, on the other hand, you have tons of files and you want to accelerate the task, you could use the -P
option of xargs to parallelize:
grep -rZli "$old" | xargs -0 -P 4 sed -i "s/$old/$new/gi"
for four parallel processes.