Linux 如何grep和replace

Linux 如何grep和replace,linux,grep,replace,Linux,Grep,Replace,我需要在目录中的所有文件和子目录中递归搜索指定的字符串,并用另一个字符串替换该字符串 我知道查找它的命令可能如下所示: grep 'string_to_find' -r ./* 但是我怎样才能用另一个字符串替换string\u to\u find的每个实例呢?通常不是用grep,而是用sed-I's/string\u to\u find/另一个字符串/g'或perl-I.bak-pe's/string\u to\u find/另一个字符串/g'我得到了答案 grep -rl matchstri

我需要在目录中的所有文件和子目录中递归搜索指定的字符串,并用另一个字符串替换该字符串

我知道查找它的命令可能如下所示:

grep 'string_to_find' -r ./*

但是我怎样才能用另一个字符串替换
string\u to\u find
的每个实例呢?

通常不是用grep,而是用
sed-I's/string\u to\u find/另一个字符串/g'
perl-I.bak-pe's/string\u to\u find/另一个字符串/g'
我得到了答案

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

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

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

这在OS X上最适合我:

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

来源:

另一个选择是将perl与globstar一起使用

.bashrc
(或任何位置)中启用
shopt-s globstar
,允许
**
全局模式递归匹配所有子目录和文件

因此,将递归地使用
perl-pXe的/SEARCH/REPLACE/g'-i**
搜索
替换为
替换

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


globstar还允许您执行类似于
sed-i的/SEARCH/REPLACE/g'***.ext
的操作,如果您想在所有扩展名为
的子文件中用
REPLACE
替换
,您甚至可以这样做:

grep 'string_to_find' -r ./*
示例

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

这将搜索与当前目录相关的所有文件中的字符串“windows”,并将每个文件中出现的字符串的“windows”替换为“linux”。

其他解决方案混合了正则表达式语法。要将perl/PCRE模式用于搜索和替换,并且只处理匹配的文件,这非常有效:

grep -rlIZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'
match1
match2
通常是相同的,但是可以简化
match1
以删除仅与替换相关的更高级功能,例如捕获组

翻译:
grep
递归并列出匹配的文件名,每个文件名用nul分隔,以保护任何特殊字符;通过管道将任何文件名传输到
xargs
,该文件名需要一个nul分隔列表;如果收到任何文件名,请将它们传递到
perl
,以执行实际的替换


对于区分大小写的匹配,从
grep
中删除
i
标志,从
s//
表达式中删除
i
模式修饰符,但从
perl
本身删除
i
标志。从
grep
中删除
I
标志以包含二进制文件。

在git repo中使用
find
sed
时要非常小心!如果不排除二进制文件,则可能会出现以下错误:

error: bad index file sha1 signature 
fatal: index file corrupt
要解决此错误,您需要通过将
新的\u字符串
替换为
旧的\u字符串
来还原
sed
。这将还原替换的字符串,因此您将回到问题的开始

搜索并替换字符串的正确方法是跳过
find
并使用
grep
,以忽略二进制文件:

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

@hobs的积分如下:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'
这将查找
/path/to/dir
下文件名中包含
文件名的所有文件,而不是查找到的每个文件,使用
searchstring
搜索该行,并将
旧的
替换为
新的

但是,如果您不想在文件名中查找带有
文件名
字符串的特定文件,只需执行以下操作:

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

这将执行与上面相同的操作,但是对于在
/path/to/dir

下找到的所有文件,我不相信grep可以做到这一点(我可能错了)。更简单的方法是使用sed或perl来执行replacingTry,即使用
sed-i的/*子字符串。*/replace/'
@Eddy\u Em,将整行替换为replace。您需要使用分组来捕获子字符串前后的行部分,然后将其放入替换行中
sed-i的/\(.*)子字符串\(.*)/\1replace\2/'
可能重复的@see-This将在匹配的文件中扫描两次。。。一次使用
grep
,然后再次使用
sed
。使用
find
方法效率更高,但您提到的这个方法确实有效。在OS X上,您需要将
sed-i的/str1/str2/g'
更改为
sed-i”“'s/str1/str2/g'
,才能工作。@cmevoli使用这个方法,
grep
浏览所有文件,而
sed
只扫描与
grep
匹配的文件。使用另一个答案中的
find
方法,
find
首先列出所有文件,然后
sed
将扫描该目录中的所有文件。因此,这种方法并不一定较慢,它取决于有多少匹配项,以及
sed
grep
find
之间的搜索速度差异。这样,您可以在实际替换之前预览grep找到的内容,大大降低失败的风险,特别是对于像myself这样的regexn00b,当您的grep替换比sed更聪明时,这也很有用。例如,ripgrep遵守.gitignore,而sed不遵守。在OS X 10.10终端上,需要参数
-i
的适当扩展字符串。例如,
find/path/to/files-type f-exec sed-i”“”s/oldstring/newstring/g“{}”无论如何,提供空字符串仍然会创建一个备份文件,这与手册中描述的不同…为什么我会得到“sed:RE错误:非法字节序列”。是的,我为OS X添加了
-I”“
。否则它会起作用。我在macOS 10.12上遇到了非法字节序列问题,这个问题/答案解决了我的问题:。这涉及到每个文件,因此修改了文件时间;并将行尾从
CRLF
转换为
LF