使用grep和sed递归查找和替换所有文件中的字符串[重复]

Posted

技术标签:

【中文标题】使用grep和sed递归查找和替换所有文件中的字符串[重复]【英文标题】:Find and Replace string in all files recursive using grep and sed [duplicate] 【发布时间】:2013-04-01 23:10:15 【问题描述】:

我得到了一个

sed: -e expression #1, char 22: unterminated `s' command 

我的脚本有问题吗? “oldstring”也有特殊字符

#!bin/bash
oldstring='<script>"[oldscript]"</script>'
newstring='<script>"[newscript]"</script>'
grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g

【问题讨论】:

方括号可能需要转义。还要双引号 sed 模式。 您的模式中的/ 也会有问题。他们应该逃脱。或者您可以为您的s 命令使用另一个分隔符(例如@)。 【参考方案1】:

sed表达式需要加引号

sed -i "s/$oldstring/$newstring/g"

【讨论】:

【参考方案2】:

正如@Didier 所说,您可以将分隔符更改为/ 以外的其他内容:

grep -rl $oldstring /path/to/folder | xargs sed -i s@$oldstring@$newstring@g

【讨论】:

鉴于 oldstring 或 newstring 的许多可能内容,上述内容会以许多有趣的方式失败。 @EdMorton,你能举个例子说明它是如何失败的吗?我知道你在下面发布了传统的做法,但只是说它可能会失败,留下如何做的问题。然后我可以理解为什么我应该你的解决方案。这些解决方案似乎更容易。谢谢 在任一字符串变量中使用任何 shell 通配符或 @ 尝试上述操作。 globbing 字符可以/将匹配您目录中的文件名,如果不是今天,那么在您最后一次期望它的未来某天,@ 将终止您的 sed 命令。如果 oldstring 在各个位置包含空格,它也会失败,更不用说任何一个字符串是否包含换行符。 OP 特别提到了the "oldstring" has special characters,所以这是一个很大的提醒,我刚刚描述的任何事情都可能发生。 还要注意,在某些环境中,尤其是 Darwin/MacOSX,您需要提供明确的备份扩展名,例如“sed -i .bak”。 @thoni56 "尤其是 Darwin/MacOSX" 也称为 BSD...【参考方案3】:

当 GNU 人将递归文件搜索引入 grep 时,他们真的搞砸了。 grep 用于在文件中查找 RE 并打印匹配行(g/re/p 还记得吗?)不是用于查找文件。有一个非常好的工具,用于查找文件的名称非常明显。 UNIX 口号“做好一件事并做好”到底发生了什么?

无论如何,以下是使用传统 UNIX 方法(未经测试)做你想做的事情的方法:

find /path/to/folder -type f -print |
while IFS= read -r file
do
   awk -v old="$oldstring" -v new="$newstring" '
      BEGIN rlength = length(old) 
      rstart = index($0,old)  $0 = substr($0,rstart-1) new substr($0,rstart+rlength) 
       print 
   ' "$file" > tmp &&
   mv tmp "$file"
done

并不是说通过使用 awk/index() 而不是 sed 和 grep,您无需转义可能出现在旧字符串或新字符串中的所有 RE 元字符,并找出用作 sed 分隔符的字符不能出现在您的旧字符串或新字符串中,并且您不需要运行 grep 因为替换只会发生在包含您想要的字符串的文件中。说了这么多,如果您不希望文件时间戳在不修改文件的情况下更改,那么只需在执行 mv 之前对 tmp 和原始文件进行 diff 或在 fgrep -q 之前抛出啊。

警告:以上内容不适用于包含换行符的文件名。如果您有这些,请告诉我们,我们可以向您展示如何处理它们。

【讨论】:

+1 当有人谈到使用sedgrep 时,他们很有可能只使用sed 或切换到awk。顺便说一句,如果您在查找中使用了 -print0,并且(在 BASH 中)使用 -d\0 应该注意文件名中包含新行。 @DavidW。正确的。当您开始谈论转义 RE 元字符以使 sed 或 grep 不会这样对待它们时,您需要切换到 awk/index() 或 fgrep 以便您可以查找字符串而不是 RE。 @josten grep-r 参数是使用 find 而不使用 awk 的替代方法。您可以使用awkfind+xargs 而不是grep+sed,结果通常会更简洁高效。使用awk 肯定不会导致您创建巨大的错综复杂的单行代码。【参考方案4】:
grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g"

【讨论】:

因此,复杂的是,名称中带有空格的文件将不会被拾取。如果你有“/files/File Two.txt”,sed 会尝试“/files/File”和“Two.txt”。【参考方案5】:
grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g'

【讨论】:

以上是关于使用grep和sed递归查找和替换所有文件中的字符串[重复]的主要内容,如果未能解决你的问题,请参考以下文章

grep和sed替换文件中的字符串

Linux批量查找与替换

如何使用 Find / Grep / Sed 在文件中查找和替换字符串

使用 grep 和 sed 在 shell 中查找和替换同一文件中的多行

递归查找和替换字符串

如何grep和替换