bash 如何使用 awk 或 sed 递归查找/替换字符串?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1583219/
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
How to do a recursive find/replace of a string with awk or sed?
提问by Tedd
How do I find and replace every occurrence of:
我如何查找和替换每次出现的:
subdomainA.example.com
with
和
subdomainB.example.com
in every text file under the /home/www/
directory tree recursively?
在/home/www/
目录树下的每个文本文件中递归?
回答by reedwolf
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
tells find
to print each of the results separated by a null character, rather than a new line. In the unlikely event that your directory has files with newlines in the names, this still lets xargs
work on the correct filenames.
-print0
告诉find
打印由空字符分隔的每个结果,而不是换行。万一您的目录包含名称中带有换行符的文件,这仍然可以xargs
处理正确的文件名。
\( -type d -name .git -prune \)
is an expression which completely skips over all directories named .git
. You could easily expand it, if you use SVN or have other folders you want to preserve -- just match against more names. It's roughly equivalent to -not -path .git
, but more efficient, because rather than checking every file in the directory, it skips it entirely. The -o
after it is required because of how -prune
actually works.
\( -type d -name .git -prune \)
是一个完全跳过所有名为.git
. 如果您使用 SVN 或想要保留其他文件夹,您可以轻松扩展它——只需匹配更多名称即可。它大致相当于-not -path .git
,但效率更高,因为它不是检查目录中的每个文件,而是完全跳过它。该-o
后则需要因为如何-prune
实际工作。
For more information, see man find
.
有关更多信息,请参阅man find
。
回答by John Zwinck
Note: Do not run this command on a folder including a git repo - changes to .git could corrupt your git index.
注意:不要在包含 git repo 的文件夹上运行此命令 - 对 .git 的更改可能会损坏您的 git 索引。
find /home/www/ -type f -exec \
sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +
Compared to other answers here, this is simpler than most and uses sed instead of perl, which is what the original question asked for.
与此处的其他答案相比,这比大多数答案更简单,并且使用 sed 而不是 perl,这是原始问题所要求的。
回答by Anatoly
The simplest way for me is
对我来说最简单的方法是
grep -rl oldtext . | xargs sed -i 's/oldtext/newtext/g'
回答by I159
All the tricks are almost the same, but I like this one:
所有的技巧几乎都一样,但我喜欢这个:
find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
find <mydir>
: look up in the directory.-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.
find <mydir>
: 在目录中查找。-type f
:文件类型:普通文件
-exec command {} +
:-exec 操作的这种变体对选定的文件运行指定的命令,但是命令行是通过在每个选定的文件名后附加来构建的;命令的总调用次数将远小于匹配文件的数量。命令行的构建方式与 xargs 构建其命令行的方式非常相似。命令中只允许出现一个“{}”实例。该命令在起始目录中执行。
回答by Employed Russian
cd /home/www && find . -type f -print0 |
xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'
回答by Robert Lujo
For me the easiest solution to remember is https://stackoverflow.com/a/2113224/565525, i.e.:
对我来说,最容易记住的解决方案是https://stackoverflow.com/a/2113224/565525,即:
sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)
NOTE: -i ''
solves OSX problem sed: 1: "...": invalid command code .
注意:-i ''
解决了 OSX 问题sed: 1: "...": invalid command code .
NOTE: If there are too many files to process you'll get Argument list too long
. The workaround - use find -exec
or xargs
solution described above.
注意:如果要处理的文件太多,您将获得Argument list too long
. 解决方法 - 使用find -exec
或xargs
上述解决方案。
回答by Jacob Wang
For anyone using silver searcher(ag
)
对于使用Silver Searcher( ag
) 的任何人
ag SearchString -l0 | xargs -0 sed -i 's/SearchString/Replacement/g'
Since ag ignores git/hg/svn file/folders by default, this is safe to run inside a repository.
由于 ag 默认忽略 git/hg/svn 文件/文件夹,因此在存储库中运行是安全的。
回答by domdambrogia
To cut down on files to recursively sed
through, you could grep
for your string instance:
要减少文件以递归方式sed
通过,您可以grep
为您的字符串实例:
grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
If you run man grep
you'll notice you can also define an --exlude-dir="*.git"
flag if you want to omit searching through .git directories, avoiding git index issues as others have politely pointed out.
如果你运行man grep
你会注意到你也可以定义一个--exlude-dir="*.git"
标志,如果你想省略搜索 .git 目录,避免其他人礼貌地指出的 git 索引问题。
Leading you to:
带领您:
grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g
回答by Jimmy Kane
An one nice oneliner as an extra. Using git grep.
一个不错的oneliner作为额外的。使用 git grep。
git grep -lz 'subdomainA.example.com' | xargs -0 perl -i'' -pE "s/subdomainA.example.com/subdomainB.example.com/g"
回答by seddonym
This one is compatible with git repositories, and a bit simpler:
这个与 git 存储库兼容,并且更简单一点:
Linux:
Linux:
git grep -l 'original_text' | xargs sed -i 's/original_text/new_text/g'
Mac:
苹果电脑:
git grep -l 'original_text' | xargs sed -i '' -e 's/original_text/new_text/g'
(Thanks to http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)
(感谢http://blog.jasonmeridth.com/posts/use-git-grep-to-replace-strings-in-files-in-your-git-repository/)