Using grep and sed to find and replace a string
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/newstr/开发者_C百科g'
This works okay. The only problem is that if the string doesn't exist then sed
fails because it doesn't get any arguments. This is a problem for me since i'm running this automatically with ANT and the build fails since sed
fails.
Is there a way to make it fail-proof in case the string is not found?
I'm interested in a one line simple solution I can use (not necessarily with grep
or sed
but with common unix commands like these).
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' {} \;
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.
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
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.
I think that without using -exec
you can simply provide /dev/null
as at least one argument in case nothing is found:
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
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.
Not sure if this will be helpful but you can use this with a remote server like the example below
ssh example.server.com "find /DIR_NAME -type f -name "FILES_LOOKING_FOR" -exec sed -i 's/LOOKINGFOR/withThisString/g' {} ;"
replace the example.server.com with your server replace DIR_NAME with your directory/file locations replace FILES_LOOKING_FOR with files you are looking for replace LOOKINGFOR with what you are looking for replace withThisString with what your want to be replaced in the file
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.
精彩评论