2013-04-10 111 views
28

我得到一个查找和替换所有文件中的字符串递归用grep和sed

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 
+1

方括号可能需要转义。也双引号sed模式。 – phs 2013-04-10 08:08:18

+3

您的模式中的'/'也会出现问题。他们应该逃脱。或者你可以使用另一个分隔符作为命令(例如'@')。 – 2013-04-10 08:13:04

回答

36

正如@Didier说,你可以将分隔符更改为其他的东西比/

grep -rl $oldstring /path/to/folder | xargs sed -i [email protected][email protected][email protected] 
+5

上面的例子会给很多有趣的方式失败,因为有很多可能的oldstring或newstring的内容。 – 2013-04-11 13:06:24

+1

@EdMorton,请你举个例子说明它是如何失败的?我知道你在下面发布了传统的做法,但只是说它可能会失败,不会留下如何做的问题。然后我可以理解为什么我应该你的解决方案。这些解决方案似乎更容易。谢谢 – 2014-03-13 07:06:48

+3

尝试上面的任何shell匹配字符或任何字符串变量中的@。 globbing字符可以/将匹配目录中的文件名,如果不是今天,那么将来的某一天,当你最后期待的时候,@会终止你的sed命令。如果oldstring在各个位置包含空格,那么也会失败,更不用说任何一个字符串包含换行符。 OP特别说'老'字符串'有特殊字符',所以这是一个大头,我刚刚描述的任何内容都可能发生。 – 2014-03-13 13:22:51

3

sed表达式需要被引用

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

当他们将递归文件搜索引入grep时,GNU人员真的搞砸了。 grep用于在文件中找到RE并打印匹配的行(g/re/p记住?)不用于查找文件。有一个非常好的工具,FINDing文件的名字非常明显。无论发生什么事,都要做一件事,做得好吗?

总之,这里是你会怎么做你想要使用传统的UNIX方式(未经测试):用AWK /指数(

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 

这并不是说),而不是SED和grep你避免需要将所有可能出现在您的旧字符串或新字符串中的RE元字符都转义出来,并找出一个字符用作不能出现在旧字符串或新字符串中的sed分隔符,并且您不需要运行grep因为替换只会发生在包含所需字符串的文件中。说了这么多,如果你不想修改文件时文件的时间戳发生变化,那么只需在执行mv之前在tmp和原始文件上进行比较,或者在执行之前在fgrep -q中输入fgrep -q AWK。

警告:以上不适用于包含换行符的文件名。如果你有这些,那么让我们知道,我们可以告诉你如何处理它们。

+2

+1当有人谈论使用'sed'和'grep'时,他们应该只使用'sed'或切换到'awk'。顺便说一句,如果你在查找中使用了'-print0',并且(在BASH中)使用'-d \ 0',应该在文件名中加入新行。 – 2013-04-11 13:02:28

+0

@DavidW。对。当你开始谈论转义RE元字符以便sed或grep不会像这样处理它们时,那​​么你需要切换到awk/index()或fgrep,以便查找字符串而不是RE。 – 2013-04-11 13:05:22

+0

@josten'grep'的'-r'参数是使用'find'不使用'awk'的替代方法。你可以用'find + xargs'而不是'grep + sed'来使用'awk',结果通常会更简洁和高效。使用'awk'肯定不会导致你创建庞大复杂的单行程序。 – 2015-02-15 19:41:29

9
grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g" 
+0

因此,与此有关的复杂情况是,名称中包含空格的文件不会被拾取。如果你有“/ files/File Two.txt”,sed会尝试“/ files/File”和“Two.txt”。 – Captainlonate 2017-10-02 02:54:39

-1
grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g'