我需要在一个目录中的所有文件和子目录中递归地搜索指定的字符串,并用另一个字符串替换此字符串。
我知道查找它的命令可能是这样的:
grep 'string_to_find' -r ./*
但是如何用另一个字符串替换string_to_find的每个实例呢?
string_to_find
通常不使用grep,而是使用sed -i 's/string_to_find/another_string/g'或perl -i.bak -pe 's/string_to_find/another_string/g'。
sed -i 's/string_to_find/another_string/g'
perl -i.bak -pe 's/string_to_find/another_string/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
来源:http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
另一种选择是在globstar中使用perl。
在你的.bashrc(或任何地方)中启用shopt -s globstar允许** glob模式递归匹配所有子目录和文件。
.bashrc
shopt -s globstar
**
perl -pXe 's/SEARCH/REPLACE/g' -i **
REPLACE
SEARCH
-X
如果你想在所有扩展名为.ext的子文件中用REPLACE替换SEARCH, globstar还允许你做类似sed -i 's/SEARCH/REPLACE/g' **/*.ext的事情。
.ext
sed -i 's/SEARCH/REPLACE/g' **/*.ext
你甚至可以这样做:
例子
grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'
这将在相对于当前目录的所有文件中搜索字符串'窗户',并在每个文件中每次出现该字符串时将'窗户'替换为'linux'。
其他解决方案混合使用正则表达式语法。要使用perl/PCRE模式进行这两个搜索和替换,并且只处理匹配的文件,这工作得很好:
grep -rlIZPi 'match1' | xargs -0r perl -pi -e 's/match2/replace/gi;'
match1和match2通常是相同的,但match2可以包含更高级的功能,这些功能只与替换相关,例如捕获组。
match1
match2
翻译:grep递归并列出匹配的文件名,每个文件名用null分隔以保护任何特殊字符;将任何文件名管道到xargs,它需要一个以空分隔的列表;如果接收到任何文件名,则将它们传递给perl以执行实际的替换。
grep
xargs
perl
对于区分大小写的匹配,从grep删除i标志,从s///表达式删除i模式修饰符,但不从perl本身删除i标志。要包含二进制文件,从grep中删除I标志。
i
s///
I
在git repo中使用find和sed时要非常小心!如果你不排除二进制文件,你会得到这样的错误:
find
sed
error: bad index file sha1 signature fatal: index file corrupt
要解决这个错误,你需要通过用你的old_string替换你的new_string来恢复sed。这将恢复替换的字符串,因此您将回到问题的起点。
old_string
new_string
搜索字符串并替换它的正确方法是跳过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下查找文件名中包含filename的所有文件,对于每一个找到的文件,搜索带有searchstring的行并将old替换为new。
/path/to/dir
filename
searchstring
old
new
不过,如果你想省略查找文件名中带有filename字符串的特定文件,则只需执行:
find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'
这将做同样的事情,但在/path/to/dir下找到的所有文件。
fd -tf -x sd 'old([Ss]tring)' 'new$1' {}
ned -R -p 'old([Ss]tring)' -r 'new$1' .
ruplacer --go 'old([Ss]tring)' 'new$1' .
要包含被忽略(通过.gitignore)和隐藏文件,你必须指定它:
.gitignore
fd
-IH
ruplacer