Find all files with text "example.html" and replace with "example.php" works only if no spaces are in file name
find public_html/ -type f -exec grep -q "$oldstring" {} \; -print0 | xargs -0 sed -i '' s@"$oldstring"@"$newstring"@g
find
will print all the filenames for which the grep
command is successful. I use the -print0
option to print them with the NUL
character as the delimiter. This goes with the -0
option to xargs
, which treats NUL
as the argument delimiter on its input, rather than breaking the input at whitespace.
Actually, you don't even need grep
and xargs
, just run sed
from find
:
find public_html/ -type f -exec sed -i '' s@"$oldstring"@"$newstring"@g {} +
Here's a lazy approach:
grep -rl $oldstring public_html/ | xargs -d'\n' sed -i "s@$oldstring@$newstring@g"
By default, xargs
uses whitespace as the delimiter of arguments coming from the input. So for example if you have two files, a b
and c
, then it will execute the command:
sed -i 's/.../.../' a b c
By telling xargs
explicitly to use newline as the delimiter with -d '\n'
it will correctly handle a b
as a single argument and quote it when running the command:
sed -i 's/.../.../' 'a b' c
I called a lazy approach, because as @Barmar pointed out, this won't work if your files have newline characters in their names. If you need to take care of such cases, then use @Barmar's method with find ... -print0
and xargs -0 ...
PS: I also changed s@"$oldstring"@"$newstring"@g
to "s@$oldstring@$newstring@g"
, which is equivalent, but more readable.