Linux 如何grep和替换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15402770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:27:31  来源:igfitidea点击:

How to grep and replace

linuxgrepreplace

提问by billtian

I need to recursively search for a specified string within all files and subdirectories within a directory and replace this string with another string.

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

I know that the command to find it might look like this:

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

grep 'string_to_find' -r ./*

But how can I replace every instance of string_to_findwith another string?

但是如何string_to_find用另一个字符串替换每个实例?

回答by minopret

Usually not with grep, but rather with sed -i 's/string_to_find/another_string/g'or perl -i.bak -pe 's/string_to_find/another_string/g'.

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

回答by billtian

I got the answer.

我得到了答案。

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

回答by rezizter

Another option is to use find and then pass it through sed.

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

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

回答by Marc Juchli

This works best for me on OS X:

这在 OS X 上最适合我:

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

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

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

回答by GuiltyDolphin

Another option would be to just use perl with globstar.

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

Enabling shopt -s globstarin your .bashrc(or wherever) allows the **glob pattern to match all sub-directories and files recursively.

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

Thus using perl -pXe 's/SEARCH/REPLACE/g' -i **will recursively replace SEARCHwith REPLACE.

因此 usingperl -pXe 's/SEARCH/REPLACE/g' -i **将递归替换SEARCHREPLACE

The -Xflag tells perl to "disable all warnings" - which means that it won't complain about directories.

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

The globstar also allows you to do things like sed -i 's/SEARCH/REPLACE/g' **/*.extif you wanted to replace SEARCHwith REPLACEin all child files with the extension .ext.

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

回答by Dulith De Costa

You could even do it like this:

你甚至可以这样做:

Example

例子

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

This will search for the string 'windows' in all files relative to the current directory and replace 'windows' with 'linux' for each occurrence of the string in each file.

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

回答by Walf

Other solutions mix regex syntaxes. To use perl/PCRE patterns for bothsearch and replace, and only process matching files, this works quite well:

其他解决方案混合了正则表达式语法。使用Perl / PCRE模式为两种搜索和替换,只有工艺匹配的文件,这个作品非常好:

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

where match1and match2are usually identical but match1may be simplified to remove more advanced features that are only relevant to the substitution, e.g. capturing groups.

wherematch1match2通常是相同的,但match1可以简化以删除仅与替换相关的更高级的功能,例如捕获组。

Translation: greprecursively and list files that match this PCRE pattern, separated by nul to protect any special characters in the filename, then pipe those filenames to xargswhich is expecting a nul-separated list, but won't do anything if no names are received, and get perlto substitute lines where matches are found.

翻译:grep递归并列出与此 PCRE 模式匹配的文件,由 nul 分隔以保护文件名中的任何特殊字符,然后将那些需要xargs以 nul 分隔的列表的文件名通过管道传输到其中,但如果没有收到名称,则不会执行任何操作,并perl找到找到匹配项的替换行。

Add the Iswitch to grepto ignore binary files. For case-sensitive matching, drop the iswitch from grep, and the iflag attached to the substitution expression, but notthe iswitch on perlitself.

添加I开关以grep忽略二进制文件。为区分大小写匹配,则删除i从开关grep,并且i连接到替换表达式标志,但不是i上开关perl本身。

回答by tsveti_iko

Be very careful when using findand sedin a git repo! If you don't exclude the binary files you can end up with this error:

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

error: bad index file sha1 signature 
fatal: index file corrupt

To solve this error you need to revert the sedby replacing your new_stringwith your old_string. This will revert your replaced strings, so you will be back to the beginning of the problem.

要解决此错误,您需要sed通过将您new_stringold_string. 这将恢复您替换的字符串,因此您将回到问题的开始。

The correct way to search for a string and replace it is to skip findand use grepinstead in order to ignore the binary files:

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

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

Credits for @hobs

@hobs 的积分

回答by tinnick

Here is what I would do:

这是我会做的:

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

this will look for all files containing filenamein the file's name under the /path/to/dir, than for every file found, search for the line with searchstringand replace oldwith new.

这将查找包含的所有文件filename在文件的名义下/path/to/dir,比中找到的每个文件,搜索与线searchstring并更换oldnew

Though if you want to omit looking for a specific file with a filenamestring in the file's name, than simply do:

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

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

This will do the same thing above, but to all files found under /path/to/dir.

这将做与上面相同的事情,但对/path/to/dir.