2013-03-14 54 views
147

我需要在目录内的所有文件和子目录中递归搜索指定的字符串,并将此字符串替换为另一个字符串。如何grep和替换

我知道的命令找出它可能是这样的:

grep 'string_to_find' -r ./* 

但我怎么能代替的string_to_find每个实例与另一个字符串?

+0

我不相信grep可以做到这一点(我可能是错的)。更简单的方法是使用sed或perl来替换 – 2013-03-14 06:41:40

+1

尝试使用'sed -i's /.*子字符串*/replace /'' – 2013-03-14 06:42:09

+1

@Eddy_Em这将用replace代替整行。您需要使用分组来捕获子字符串前后的部分行,然后将其放入替换行中。 'sed -i's/\(。* \)substring \(。* \)/ \ 1replace \ 2 /'' – JStrahl 2014-08-05 07:50:37

回答

1

通常不是用grep,而是用sed -i 's/string_to_find/another_string/g'perl -i.bak -pe 's/string_to_find/another_string/g'

102

我得到了答案。

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g' 
+11

这将扫描两次匹配的文件...一次使用'grep',然后使用'sed '。使用'find'方法更高效,但是您提到的这种方法确实有效。 – cmevoli 2013-03-14 10:27:18

+24

在OS X上,您需要将'sed -i's/str1/str2/g''更改为'sed -i'“'s/str1/str2/g''才能正常工作。 – jdf 2015-07-07 22:53:01

+2

@jdf这是为什么? – chishaku 2016-07-26 15:16:07

158

另一个选择是使用find然后通过sed传递它。

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \; 
+24

在OS X 10.10终端上,需要一个到参数'-i'的正确扩展字符串。例如,'find/path/to/files -type f -exec sed -i'“”s/oldstring/new string/g“{} \;'无论如何,提供空字符串仍然会创建一个备份文件, ... – Eonil 2015-06-25 02:41:06

+5

为什么我会得到“sed:RE错误:非法字节序列”。是的,我为OS X添加了“-i”“',否则它会起作用。 – taco 2016-06-16 19:51:01

+0

我在macOS 10.12上有非法字节序列问题,并且这个问题/答案解决了我的问题:http://stackoverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x 。 – abeboparebop 2017-04-11 08:12:14

25

这个最适合我的OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi 

来源:http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files

+0

这是完美的!也适用于ag:'ag“search”-l -r。 |排序| uniq | xargs perl -e's/search/replace'-pi' – 2016-03-04 11:24:59

+1

'sort -u'可以代替'sort | uniq' – 2016-03-05 00:41:14

+0

@sebastiankeller你的Perl命令缺少最后一个斜杠,这是一个语法错误。 – tripleee 2016-06-11 08:12:13

0

另一种选择是只用perl与globstar。

在您的.bashrc(或任何地方)启用shopt -s globstar允许** glob模式递归匹配所有子目录和文件。

因此使用perl -pXe 's/SEARCH/REPLACE/g' -i **将递归地 替换SEARCHREPLACE

-X标志告诉perl“禁用所有警告” - 这意味着它不会抱怨目录。

的globstar还允许你做这样的事情sed -i 's/SEARCH/REPLACE/g' **/*.ext如果你想与REPLACE在所有子文件扩展名为.ext更换SEARCH

+0

*“另一种选择是使用perl和globstar ...”* - 不在Posixy机器上,如Solaris。这就是为什么我特意寻找'grep'和'sed'。 – jww 2017-10-25 00:20:31

19

你甚至可以遵循这样的..

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g' 

这将为字符串中的所有文件的相对“窗口”搜索到当前目录和替换“窗口'与'linux',每个文件中每个字符串的出现次数。

+2

只有存在不应修改的文件时,'grep'才有用。在所有文件上运行'sed'会更新文件的修改日期,但如果没有匹配则保持内容不变。 – tripleee 2016-06-11 08:10:46

+0

@tripleee:注意* ...但[sed]保持内容不变,如果没有匹配“*。当使用'-i'时,我相信'sed'会改变它接触到的每个文件的文件时间,甚至虽然内容没有变化,但是'sed'也会转换行结束符,因为所有的'CRLF'都被改为'LF',所以我没有在Windows的'sed'中使用git repo。 – jww 2017-10-25 00:19:01

3

其他解决方案混合使用正则表达式语法。使用Perl/PCRE模式为搜索和替换,避免加工的每一个文件,这个工作得很好:

grep -rlZP 'match1' | xargs -0r perl -pi -e 's/match2/replace/g;' 

其中match1match2通常是相同的,但match1可以简化去除更多的先进功能,只与替代有关,例如捕获组。

翻译︰grep递归和列出匹配的文件,由nul分隔以保护文件名中的任何特殊字符,匹配此PCRE模式,然后管这些文件名xargs期望一个空分隔的列表,但不会如果没有收到任何名字,请做任何事情,然后让perl重写每个文件,替换找到匹配的行。

I选项添加到grep以忽略二进制文件。

+0

Perl本身非常有能力递归一个文件结构,事实上,有一个工具['find2perl'](https://perldoc.perl.org/5.8.8/find2perl.html),它随Perl一起提供,它没有任何'xargs'欺骗。 – tripleee 2017-10-25 03:24:27

+0

@tripleee'find'不搜索文件内容,关键是只处理匹配的文件而无需编写Perl程序。 – Walf 2017-10-25 05:30:15

-3

找到&替换文件的vi模式 的语法如下: :%s/WORD找到的-HERE /替换词,这里/ G

OR :%s/FindMe/ReplaceME /克

实例

的替代命令可用于按您的要求。