Linux 使用grep和sed查找并替换所有递归文件中的字符串

Linux 使用grep和sed查找并替换所有递归文件中的字符串,linux,bash,recursion,sed,grep,Linux,Bash,Recursion,Sed,Grep,我得到一份工作 sed:-e表达式#1,char 22:unterminated`s'命令 我的剧本有问题吗?“oldstring”也有特殊字符 #!bin/bash oldstring='<script>"[oldscript]"</script>' newstring='<script>"[newscript]"</script>' grep -rl $oldstring /path/to/folder | xargs sed -i s/$o

我得到一份工作

sed:-e表达式#1,char 22:unterminated`s'命令
我的剧本有问题吗?“oldstring”也有特殊字符

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

sed
表达式需要引用

sed-i“s/$oldstring/$newstring/g”

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

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

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

不管怎样,下面是使用传统UNIX方法(未经测试)做您想做的事情的方法:

并不是说,通过使用awk/index()而不是sed和grep,可以避免转义旧字符串或新字符串中可能出现的所有RE元字符,并找出一个字符用作旧字符串或新字符串中不能出现的sed分隔符,而且您不需要运行grep,因为替换只会发生在确实包含所需字符串的文件中。话虽如此,如果您不想在不修改文件的情况下更改文件时间戳,那么只需在执行mv之前对tmp和原始文件执行一个diff,或者在awk之前插入一个fgrep-q


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

方括号可能需要转义。另外,还要双引号引用sed模式。您的模式中的
/
也会有问题。他们应该逃走。或者您可以为您的
s
命令使用另一个分隔符(例如
@
)。+1当有人谈论将
sed
grep
一起使用时,他们很有可能只使用
sed
或切换到
awk
。顺便说一下,如果您在查找中使用了
-print0
,并且(在BASH中)使用了
-d\0
,则应该注意文件名中有新行。@DavidW。正确的。当你开始谈论转义RE元字符,以便sed或grep不会这样对待它们时,你需要切换到awk/index()或fgrep,这样你就可以查找字符串而不是REs.@josten
-r
arg for
grep
是使用
find
而不是使用
awk
的替代方法。您可以将
awk
find+xargs
一起使用,而不是
grep+sed
,结果通常会更加简洁高效。使用
awk
肯定不会导致您创建大量复杂的单行程序。鉴于oldstring或newstring的内容可能如此之多,上述操作可能会以许多有趣的方式失败。@EdMorton,请举例说明它是如何失败的?我知道你在下面发布了传统的做法,但仅仅说它可能会失败,就留下了如何做的问题。那我就明白我为什么要用你的解决方案了。这些解决方案似乎简单得多。在任何一个字符串变量中使用任何shell全局字符或@表示上述内容。globbing字符可以/将匹配目录中的文件名,如果今天不匹配,那么在将来某一天,当您最后期望它时,@将终止您的sed命令。如果oldstring在不同位置包含空格,它也会失败,更不用说其中任何一个字符串是否包含换行符了。OP特别指出,
“oldstring”具有特殊字符
,因此这是一个大问题,我刚才描述的任何内容以及更多内容都可能发生。另外,请注意,在某些环境中,尤其是Darwin/MacOSX,您需要提供一个显式备份扩展名,如“sed-I.bak”。@thoni56“特别是Darwin/MacOSX”也被称为BSD…所以它的复杂之处在于,文件名中带有空格的文件不会被拾取。如果您有“/files/filetwo.txt”,sed将尝试使用“/files/File”和“Two.txt”。
grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g"
grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g"
grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g'