使用 grep 和 sed 查找和替换字符串

我使用以下方法递归地搜索一个目录中的特定字符串,并将其替换为另一个字符串:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g'

这样就行了。唯一的问题是,如果字符串不存在,那么 sed将失败,因为它没有得到任何参数。这对我来说是一个问题,因为我正在运行这个自动与 ANT 和构建失败,因为 sed失败。

是否有一种方法可以使它不会出现故障,以防找不到字符串?

我感兴趣的是一个我可以使用的一行简单解决方案(不一定与 grepsed一起使用,但是与这些常见的 unix 命令一起使用)。

141878 次浏览

您可以使用 find-exec直接进入 sed,而不是首先定位 oldstrgrep。可能效率会低一点,但这可能不重要。这样,对 find列出的所有文件执行 sed替换,但是如果没有 oldstr,它显然不会对其进行操作。

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;

标准的 xargs没有很好的方法来做到这一点; 您最好像别人建议的那样使用 find -exec,或者将 sed包装在一个脚本中,如果没有参数,这个脚本什么也不做。GNU xargs--no-run-if-empty选项,而 BSD/OS X xargs-L选项,看起来它应该做类似的事情。

如果要替换固定的字符串或某种模式,我还想添加 bash 内建模式字符串替换变量替换构造。我没有自己描述,而是引用 bash 手册中的一节:

${parameter/pattern/string}

模式被扩展以生成一个模式,就像在路径名中一样 扩张。展开 参数,将 模式与其值的最长匹配替换为 绳子。如果 模式/开始,模式的所有匹配项都替换为字符串。 通常只有第一个匹配被替换。如果 模式开始 对于 #,它必须在 参数 。如果 模式%开头,则它必须在结尾处匹配 如果 绳子为空,则匹配 的 模式被删除,而 模式后面的 /可能被省略。如果 参数@*,则替换操作为 依次应用于每个位置参数,并且展开 是结果列表。如果 参数是下标为 @*的数组变量,则将替换操作应用于 数组的每个成员依次进行,扩展为 结果清单。

我认为,如果没有使用 -exec,你可以简单地提供 /dev/null作为至少一个参数,以防什么也找不到:

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

我采纳了弗拉德的想法,稍微改动了一下

grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' /dev/null

也就是说

sed: couldn't edit /dev/null: not a regular file

我正在做三个不同的连接到远程服务器

touch deleteme
grep -rl oldstr path | xargs sed -i 's/oldstr/newstr/g' ./deleteme
rm deleteme

虽然这样做不那么优雅,并且需要两个以上的连接到服务器(也许有一种方法可以在一行中完成所有的工作) ,但是它也能有效地完成工作

你的解决方案是可行的。只能这样试试:

files=$(grep -rl oldstr path) && echo $files | xargs sed....

因此,只有当 grep 返回 0时才执行 xargs,例如,当在某些文件中找到字符串时。

我的用例是我想要替换 foo:/Drive_Letterfoo:/bar/baz/xyz 在我的例子中,我可以用下面的代码来完成。 我在同一个目录位置,那里有大量的文件。

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

希望能帮上忙。

不确定这是否有帮助,但是您可以像下面的示例那样在远程服务器上使用它

Ssh example.server.com 为“ find/DIR _ NAME-type f-name“ FILES _ LooKING _ FOR”-exec sed-i’s/LOOKINGFOR/withThisString/g’{} ;

用服务器替换 example.server.com 用目录/文件位置替换 DIR _ NAME 用要查找的文件替换 FILES _ LOOKING _ FOR 用你正在寻找的东西代替寻找 用您希望在文件中替换的内容替换为 ThisString