How to do a recursive find/replace of a string with awk or sed?
如何找到并替换每次出现的事件:
1 | subdomainA.example.com |
同
1 | subdomainB.example.com |
在
1 | find /home/www \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' |
来自
-print0 (GNU
find only) tellsfind to use the null character (\0 ) instead of whitespace as the output delimiter between pathnames found. This is a safer option if your files can contain blanks or other special characters. It is recommended to use the-print0 argument tofind if you use-exec orxargs (the-0 argument is needed inxargs .)
注意:不要在包含git repo的文件夹上运行此命令 - 更改为.git可能会损坏您的git索引。
1 2 | find /home/www/ -type f -exec \ sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + |
与此处的其他答案相比,这比大多数答案更简单,并使用sed而不是perl,这是原始问题所要求的。
对我来说最简单的方法是
1 | grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g' |
所有技巧几乎相同,但我喜欢这个:
1 | find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} + |
-
find :在目录中查找。 -
-type f :File is of type: regular file
-
-exec command {} + :This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending
each selected file name at the end; the total number of invocations of the command will be much less than the number of
matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of
`{}' is allowed within the command. The command is executed in the starting directory.
1 2 | cd /home/www && find . -type f -print0 | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' |
对我来说,最简单的解决方案是https://stackoverflow.com/a/2113224/565525,即:
1 | sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f) |
注意:
注意:如果要处理的文件太多,您将获得
对于任何使用银色搜索器的人(
1 | ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g' |
由于ag默认忽略git / hg / svn文件/文件夹,因此可以安全地在存储库中运行。
要将文件减少为递归
1 | grep -rl /path/to/folder | xargs sed -i s^^<newstring>^g |
如果你运行
引导您:
1 | grep -rl --exclude-dir="*.git" /path/to/folder | xargs sed -i s^^<newstring>^g |
一个不错的oneliner作为额外的。使用git grep。
1 | git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE"s/subdomainA.example.com/subdomainB.example.com/g" |
这个与git存储库兼容,有点简单:
Linux的:
1 | git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g' |
苹果电脑:
1 | git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g' |
(感谢http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)
1 | find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + |
"-exec"标志告诉find在找到的每个文件上运行以下命令。
1 | perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} + |
是对文件运行的命令(一次多个)。
命令末尾的
根据
"命令行的构建方式大致相同
xargs构建了命令行。"
因此,可以在不使用
我只需要这个并且对可用示例的速度不满意。所以我想出了自己的:
1 | cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' |
Ack-grep在查找相关文件方面非常有效。这个命令轻而易举地取代了~14.5万个文件,而其他文件花费了很长时间,我不能等到它们完成。
我猜大多数人都不知道他们可以将某些内容传递到"while read file"中,它可以避免那些讨厌的-print0 args,同时在文件名中预先设置空格。
在sed之前进一步添加
您可以使用awk解决此问题,如下所示,
1 2 3 4 | for file in `find /home/www -type f` do awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file; done |
希望对你有帮助 !!!
试试这个:
1 | sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *` |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/usr/local/bin/bash -x find * /home/www -type f | while read files do sedtest=$(sed -n '/^/,/$/p'"${files}" | sed -n '/subdomainA/p') if ["${sedtest}" ] then sed s'/subdomainA/subdomainB/'g"${files}">"${files}".tmp mv"${files}".tmp"${files}" fi done |
这是一个应该比大多数更通用的版本;例如,它不需要
1 | du -a | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g' |
如果要添加文件扩展名等过滤器,请使用
1 | du -a | grep"\.scala$" | awk -F' ' '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g' |
我只是使用上衣:
1 2 | find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 | xargs -0 tops -verbose replace"verify_noerr(<b args>)" with"__Verify_noErr()" \ replace"check(<b args>)" with"__Check()" |
根据这篇博文:
1 | find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;' |
有点老派,但这适用于OS X.
几乎没有技巧:
?仅编辑当前目录下扩展名为
?必须转义
?
另请注意,这是编辑一个Jinja模板以在
首先,验证您的sed命令是否符合要求(这只会将更改打印到stdout,它不会更改文件):
1 2 | for file in $(find . -name *.sls -type f); do echo -e" $file:"; sed 's,foo\.bar,foo/bar/"+baz+"/,g' $file; done |
准备好进行更改后,根据需要编辑sed命令:
1 2 | for file in $(find . -name *.sls -type f); do echo -e" $file:"; sed -i '' 's,foo\.bar,foo/bar/"+baz+"/,g' $file; done |
请注意sed命令中的
快乐的人们!
只是为了避免改变
- NearlysubdomainA.example.com
- subdomainA.example.comp.other
但仍然
- subdomainA.example.com.IsIt.good
(也许在域根背后的想法不好)
1 | find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \; |
如果您不介意将
这是交易:
-
以递归方式grep查找要在特定路径中替换的字符串,并仅获取匹配文件的完整路径。 (那将是
$(grep 'string' 'pathname' -Rl) 。 -
(可选)如果要在集中目录中对这些文件进行预备,也可以使用它:
cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname' -
之后,您可以按照类似于给定链接上提供的方案,在
vim 中随意编辑/替换:-
:bufdo %s#string#replacement#gc | update
-
要替换git存储库中的所有匹配项,您可以使用:
1 | git ls-files -z | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' |
请参阅本地git repo中的列表文件?用于列出存储库中所有文件的其他选项。
1 | perl -p -i -e 's/oldthing/new_thingy/g' `grep -ril oldthing *` |
使用
1 2 3 4 | for pp in $(grep -Rl looking_for_string) do sed -i 's/looking_for_string/something_other/g'"${pp}" done |
更改多个文件(并将备份保存为
1 | perl -p -i -e"s/\|/x/g" * |
将获取目录中的所有文件并将
被称为"Perl馅饼"(简单的馅饼)
对于IBMi上的Qshell(qsh),不是由OP标记的bash。
qsh命令的局限性:
- find没有-print0选项
- xargs没有-0选项
- sed没有-i选项
因此qsh中的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | PATH='your/path/here' SEARCH=\'subdomainA.example.com\' REPLACE=\'subdomainB.example.com\' for file in $( find ${PATH} -P -type f ); do TEMP_FILE=${file}.${RANDOM}.temp_file if [ ! -e ${TEMP_FILE} ]; then touch -C 819 ${TEMP_FILE} sed -e 's/'$SEARCH'/'$REPLACE'/g' \ < ${file} > ${TEMP_FILE} mv ${TEMP_FILE} ${file} fi done |
注意事项:
- 解决方案不包括错误处理
- 不是由OP标记的Bash
如果您想在不完全破坏SVN存储库的情况下使用它,可以通过执行以下操作告诉"find"忽略所有隐藏文件:
1 | find . \( ! -regex '.*/\..*' \) -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g' |
如果您需要排除目录(
1 | grep -rlZ oldtext . --exclude-dir=.svn | xargs -0 sed -i 's/oldtext/newtext/g' |
将所有匹配string_1的内??容替换为当前目录和子目录中所有.c和.h文件的string_2(不包括.git /)。
这适用于Mac:
1 2 | find . -type f -path"*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i '' -e 's/'$1'/'$2'/g' {} + |
这应该适用于Linux(尚未测试):
1 2 | find . -type f -path"*.git*" -prune -o -name '*\.[ch]' -exec \ sed -i 's/string_1/string_2/g' {} + |
这是我为OSX和Windows(msys2)找到的最佳解决方案。应该可以使用任何可以获得sed的gnu版本的东西。跳过.git目录,这样它就不会破坏你的校验和。
在Mac上,只需先安装coreutils并确保gsed在路径中 -
1 | brew install coreutils |
然后我把这个函数粘贴在我的zshrc / bashrc - >中
1 2 3 4 5 6 | replace-recursive() { hash gsed 2>/dev/null && local SED_CMD="gsed" || SED_CMD="sed" find . -type f -name"*.*" -not -path"*/.git/*" -print0 | xargs -0 $SED_CMD -i"s/$1/$2/g" } usage: replace-recursive <find> <replace> |
一种更简单的方法是在命令行中使用以下内容
1 | find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g' |
如果您有权访问节点,则可以执行
1 | rexreplace 'subdomainA.example.com' 'subdomainB.example.com' /home/www/**/*.* |