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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:36:56  来源:igfitidea点击:

How to do a recursive find/replace of a string with awk or sed?

bashsedawkreplace

提问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'

-print0tells findto 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 xargswork 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 -oafter it is required because of how -pruneactually 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 -execor xargssolution described above.

注意:如果要处理的文件太多,您将获得Argument list too long. 解决方法 - 使用find -execxargs上述解决方案。

回答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 sedthrough, you could grepfor your string instance:

要减少文件以递归方式sed通过,您可以grep为您的字符串实例:

grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

If you run man grepyou'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/