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

时间:2011-05-30 16:10:08

标签: linux shell unix sed grep

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

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

这没关系。唯一的问题是如果字符串不存在则sed失败,因为它没有得到任何参数。这对我来说是一个问题,因为我使用ANT自动运行它,并且由于sed失败,构建失败。

如果找不到字符串,有没有办法使其防止失败?

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

8 个答案:

答案 0 :(得分:69)

您可以将find-exec直接用于sed,而不是首先使用oldstr找到grep。效率可能稍低,但这可能并不重要。这样,对sed列出的所有文件执行find替换,但如果oldstr不存在,则显然不会对其进行操作。

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

答案 1 :(得分:9)

你的解决方案没问题。只能这样试试:

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

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

答案 2 :(得分:7)

标准xargs无法做到这一点;你最好不要像其他人建议的那样使用find -exec,或者将sed包装在一个脚本中,如果没有参数则不会做任何事情。 GNU xargs具有--no-run-if-empty选项,而BSD / OS X xargs具有-L选项,看起来它应该做类似的事情。

答案 3 :(得分:7)

我采取了弗拉德的想法并改变了一点。而不是

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

哪个收益

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

我正在与远程服务器建立3个不同的连接

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

虽然这不那么优雅,并且需要2个与服务器的连接(也许有一种方法可以在一行中完成),它也可以有效地完成工作

答案 4 :(得分:4)

我认为如果不使用-exec,您只需提供/dev/null作为至少一个参数,以防无法找到:

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

答案 5 :(得分:1)

我的用例是我想要替换 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' 在我的情况下,我能够使用以下代码完成它。 我在大量文件的同一目录位置。

{{1}}

希望有所帮助。

答案 6 :(得分:0)

不确定这是否有帮助,但是您可以将其用于远程服务器,如下面的示例

ssh example.server.com“找到/ DIR_NAME-类型f-名称” FILES_LOOKING_FOR“ -exec sed -i's / LOOKINGFOR / withThisString / g'{};”

将example.server.com替换为服务器 将DIR_NAME替换为您的目录/文件位置 用您要查找的文件替换FILES_LOOKING_FOR 用您要寻找的代替LOOKINGFOR 用要替换的文件替换thisString

答案 7 :(得分:-1)

如果要替换固定字符串或某些模式,我还想添加bash内置模式字符串替换变量替换构造。我不是自己描述,而是引用bash手册中的部分:

  

${parameter/pattern/string}

     

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