使用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 当有人谈到使用sed
和grep
时,他们很有可能只使用sed
或切换到awk
。顺便说一句,如果您在查找中使用了 -print0
,并且(在 BASH 中)使用 -d\0
应该注意文件名中包含新行。
@DavidW。正确的。当您开始谈论转义 RE 元字符以使 sed 或 grep 不会这样对待它们时,您需要切换到 awk/index() 或 fgrep 以便您可以查找字符串而不是 RE。
@josten grep
的 -r
参数是使用 find
而不使用 awk
的替代方法。您可以使用awk
和find+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递归查找和替换所有文件中的字符串[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Find / Grep / Sed 在文件中查找和替换字符串