I am using the following to search a directory recursively for specific string and replace it with another:
grep -rl oldstr path | xargs sed -i \'s/oldstr/ne
My use case was I wanted to replace
foo:/Drive_Letter
with foo:/bar/baz/xyz
In my case I was able to do it with the following code.
I was in the same directory location where there were bulk of files.
find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'
hope that helped.
Your solution is ok. only try it in this way:
files=$(grep -rl oldstr path) && echo $files | xargs sed....
so execute the xargs
only when grep return 0
, e.g. when found the string in some files.
Standard xargs
has no good way to do it; you're better off using find -exec
as someone else suggested, or wrap the sed
in a script which does nothing if there are no arguments. GNU xargs
has the --no-run-if-empty
option, and BSD / OS X xargs
has the -L
option which looks like it should do something similar.
You can use find
and -exec
directly into sed
rather than first locating oldstr
with grep
. It's maybe a bit less efficient, but that might not be important. This way, the sed
replacement is executed over all files listed by find
, but if oldstr
isn't there it obviously won't operate on it.
find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
I have taken Vlad's idea and changed it a little bit. Instead of
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
Which yields
sed: couldn't edit /dev/null: not a regular file
I'm doing in 3 different connections to the remote server
touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme
Although this is less elegant and requires 2 more connections to the server (maybe there's a way to do it all in one line) it does the job efficiently as well
If you are to replace a fixed string or some pattern, I would also like to add the bash builtin pattern string replacement variable substitution construct. Instead of describing it myself, I am quoting the section from the bash manual:
${parameter/pattern/string}
The pattern is expanded to produce a pattern just as in pathname expansion. parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with
/
, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with#
, it must match at the beginning of the expanded value of parameter. If pattern begins with%
, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the/
following pattern may be omitted. If parameter is@
or*
, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with@
or*
, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.