Linux 使用 grep 和 sed 查找和替换字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6178498/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using grep and sed to find and replace a string
提问by Michael
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 sedfails 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 sedfails.
这工作正常。唯一的问题是,如果字符串不存在,则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 grepor sedbut with common unix commands like these).
我对我可以使用的单行简单解决方案感兴趣(不一定使用grep或sed但使用这些常见的 unix 命令)。
采纳答案by Michael Berkowski
You can use findand -execdirectly into sedrather than first locating oldstrwith grep. It's maybe a bit less efficient, but that might not be important. This way, the sedreplacement is executed over all files listed by find, but if oldstrisn't there it obviously won't operate on it.
您可以使用find和-exec直接进入sed,而不是第一个定位oldstr用grep。它可能效率稍低,但这可能并不重要。这样,sed替换将在 列出的所有文件上执行find,但如果oldstr不存在,它显然不会对其进行操作。
find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;
回答by geekosaur
Standard xargshas no good way to do it; you're better off using find -execas someone else suggested, or wrap the sedin a script which does nothing if there are no arguments. GNU xargshas the --no-run-if-emptyoption, and BSD / OS X xargshas the -Loption which looks like it should do something similar.
标准xargs没有很好的方法来做到这一点;您最好find -exec按照其他人的建议使用,或者将其包装sed在一个脚本中,如果没有参数则不执行任何操作。GNUxargs有这个--no-run-if-empty选项,而 BSD / OS Xxargs有这个-L选项,看起来它应该做类似的事情。
回答by phoxis
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. parameteris expanded and the longest match of patternagainst its value is replaced with string. If patternbegins with
/, all matches of patternare replaced with string. Normally only the first match is replaced. If patternbegins with#, it must match at the beginning of the expanded value of parameter. If patternbegins with%, it must match at the end of the expanded value of parameter. If stringis null, matches of patternare deleted and the/following patternmay be omitted. If parameteris@or*, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameteris 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.
${parameter/pattern/string}模式被扩展以产生一个模式,就像在路径名扩展中一样。 参数被扩展,模式与其值的最长匹配被替换为 string。如果 模式开头
/,所有的比赛模式被替换为的字符串。通常只替换第一个匹配项。如果 模式以 开头#,则它必须匹配参数扩展值的开头 。如果模式以 开头%,则必须匹配参数扩展值的末尾. 如果string为 null,则删除pattern 的匹配项,并且可以省略/以下模式。如果 参数是@或*,则对每个位置参数依次进行替换操作,展开的结果就是列表。如果parameter是一个以@or*为下标的数组变量,则替换操作依次应用于数组的每个成员,扩展为结果列表。
回答by phoxis
I think that without using -execyou can simply provide /dev/nullas 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
回答by Michael
I have taken Vlad's idea and changed it a little bit. Instead of
我采纳了 Vlad 的想法并对其进行了一些更改。代替
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
虽然这不太优雅并且需要 2 个以上的服务器连接(也许有一种方法可以在一行中完成所有工作),但它也能有效地完成工作
回答by jm666
Your solution is ok. only try it in this way:
你的解决方案没问题。只能这样试试:
files=$(grep -rl oldstr path) && echo $files | xargs sed....
so execute the xargsonly when grep return 0, e.g. when found the string in some files.
所以xargs只在 grep 返回时执行0,例如在某些文件中找到字符串时。
回答by neo7
My use case was I wanted to replace
foo:/Drive_Letterwith foo:/bar/baz/xyzIn 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.
希望有所帮助。

