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/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.
这是好的。唯一的问题是,如果字符串不存在,那么sed失败,因为它没有任何参数。这对我来说是一个问题,因为我正在用ANT自动运行它,而构建失败了,因为sed失败了。
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).
我感兴趣的是一种我可以使用的简单解决方案(不一定是针对grep或sed,而是针对这些常见的unix命令)。
7 个解决方案
#1
66
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和-exec到sed中,而不是首先使用grep查找oldstr。这可能有点低效,但这可能并不重要。通过这种方式,对find列出的所有文件执行sed替换,但是如果oldstr不在,那么它显然不会对它进行操作。
find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
#2
9
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.
因此,只有当grep返回0时才执行xargs,例如在某些文件中找到该字符串时。
#3
7
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.
标准的xargs没有好的方法;最好像其他人建议的那样使用find -exec,或者将sed封装在一个脚本中,如果没有参数,这个脚本什么都不做。GNU xargs有—无-运行-空选项,BSD / OS X xargs有-L选项,看起来应该做类似的事情。
#4
7
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
我正在做3个不同的连接到远程服务器
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
尽管这是不那么优雅的,并且需要两个更多的连接到服务器(也许有一种方法可以做到这一点),它也能有效地完成工作。
#5
4
I think that without using -exec
you can simply provide /dev/null
as at least one argument in case nothing is found:
我认为,如果不使用-exec,您可以提供/dev/null作为至少一个参数,以防什么都找不到:
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
#6
1
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.
我的用例是,我想用foo:/Drive_Letter替换为foo:/bar/baz/xyz,在我的用例中,我可以用下面的代码替换它。我在同一目录位置,那里有大量的文件。
find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'
hope that helped.
希望帮助。
#7
-1
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:
如果要替换一个固定字符串或某个模式,我还想添加bash内置模式字符串替换变量替换构造。我没有自己描述它,而是引用了bash手册中的一节:
${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.模式被扩展为产生模式,就像路径名扩展一样。扩展参数,使用字符串替换模式对其值的最长匹配。如果模式以/开头,则模式的所有匹配将被字符串替换。通常只有第一场比赛被替换。如果模式以#开头,那么它必须在参数的扩展值的开始处匹配。如果模式以%开头,则必须在参数的展开值末尾匹配。如果字符串为空,则删除模式的匹配,并删除/以下模式。如果参数为@或*,则依次对每个位置参数应用替换操作,扩展为结果列表。如果参数是一个带有@或*的下标数组变量,那么替换操作将依次应用于数组的每个成员,扩展是结果列表。
#1
66
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和-exec到sed中,而不是首先使用grep查找oldstr。这可能有点低效,但这可能并不重要。通过这种方式,对find列出的所有文件执行sed替换,但是如果oldstr不在,那么它显然不会对它进行操作。
find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
#2
9
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.
因此,只有当grep返回0时才执行xargs,例如在某些文件中找到该字符串时。
#3
7
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.
标准的xargs没有好的方法;最好像其他人建议的那样使用find -exec,或者将sed封装在一个脚本中,如果没有参数,这个脚本什么都不做。GNU xargs有—无-运行-空选项,BSD / OS X xargs有-L选项,看起来应该做类似的事情。
#4
7
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
我正在做3个不同的连接到远程服务器
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
尽管这是不那么优雅的,并且需要两个更多的连接到服务器(也许有一种方法可以做到这一点),它也能有效地完成工作。
#5
4
I think that without using -exec
you can simply provide /dev/null
as at least one argument in case nothing is found:
我认为,如果不使用-exec,您可以提供/dev/null作为至少一个参数,以防什么都找不到:
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null
#6
1
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.
我的用例是,我想用foo:/Drive_Letter替换为foo:/bar/baz/xyz,在我的用例中,我可以用下面的代码替换它。我在同一目录位置,那里有大量的文件。
find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'
hope that helped.
希望帮助。
#7
-1
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:
如果要替换一个固定字符串或某个模式,我还想添加bash内置模式字符串替换变量替换构造。我没有自己描述它,而是引用了bash手册中的一节:
${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.模式被扩展为产生模式,就像路径名扩展一样。扩展参数,使用字符串替换模式对其值的最长匹配。如果模式以/开头,则模式的所有匹配将被字符串替换。通常只有第一场比赛被替换。如果模式以#开头,那么它必须在参数的扩展值的开始处匹配。如果模式以%开头,则必须在参数的展开值末尾匹配。如果字符串为空,则删除模式的匹配,并删除/以下模式。如果参数为@或*,则依次对每个位置参数应用替换操作,扩展为结果列表。如果参数是一个带有@或*的下标数组变量,那么替换操作将依次应用于数组的每个成员,扩展是结果列表。