命令行:在 grep 匹配的所有文件名中搜索并替换

发布于 2024-07-11 16:13:30 字数 216 浏览 11 评论 0原文

我正在尝试搜索并替换 grep 匹配的所有文件中的字符串:

grep -n 'foo' * 将以以下形式提供输出:

[filename]:[line number]:[text]

对于 grep 返回的每个文件,我想通过将 foo 替换为 bar 来修改文件。

I'm trying to search and replace a string in all files matched by grep:

grep -n 'foo' * will give me output in the form:

[filename]:[line number]:[text]

For each file returned by grep, I'd like to modify the file by replacing foo with bar.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

听风吹 2024-07-18 16:13:30

根据您给出的示例,这似乎是您想要的:

sed -i 's/foo/bar/g' *

它不是递归的(它不会下降到子目录中)。 对于在整个树中替换选定文件的良好解决方案,我将使用 find:

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

*.html 是文件必须匹配的表达式,之后的 .bak -i 制作原始文件的副本,带有 .bak 扩展名(可以是您喜欢的任何扩展名),sed 表达式末尾的 g 告诉 sed 替换多个复制一行(而不是仅复制第一行)。 -print to find 可以方便地显示哪些文件正在匹配。 所有这些都取决于您系统上这些工具的确切版本。

This appears to be what you want, based on the example you gave:

sed -i 's/foo/bar/g' *

It is not recursive (it will not descend into subdirectories). For a nice solution replacing in selected files throughout a tree I would use find:

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

The *.html is the expression that files must match, the .bak after the -i makes a copy of the original file, with a .bak extension (it can be any extension you like) and the g at the end of the sed expression tells sed to replace multiple copies on one line (rather than only the first one). The -print to find is a convenience to show which files were being matched. All this depends on the exact versions of these tools on your system.

蓝海 2024-07-18 16:13:30

您的意思是在 grep 匹配的所有文件中搜索并替换字符串吗?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

编辑

因为这似乎是一个相当受欢迎的问题,我想更新一下。

现在我主要使用 ack-grep,因为它更加用户友好。 所以上面的命令是:

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

要处理文件名中的空格,您可以运行:

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

您可以使用 ack-grep 执行更多操作。 假设您只想将搜索限制为 HTML 文件:

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

如果空格不是问题,它会更短:

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files

Do you mean search and replace a string in all files matched by grep?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

Edit

Since this seems to be a fairly popular question thought I'd update.

Nowadays I mostly use ack-grep as it's more user-friendly. So the above command would be:

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

To handle whitespace in file names you can run:

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

you can do more with ack-grep. Say you want to restrict the search to HTML files only:

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

And if white space is not an issue it's even shorter:

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
滥情哥ㄟ 2024-07-18 16:13:30

如果您的 sed(1)-i 选项,请像这样使用它:

for i in *; do
  sed -i 's/foo/bar/' $i
done

如果没有,则根据您想要使用的语言,有以下几种方法的变体玩:

ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *

If your sed(1) has a -i option, then use it like this:

for i in *; do
  sed -i 's/foo/bar/' $i
done

If not, there are several ways variations on the following depending on which language you want to play with:

ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *
清风疏影 2024-07-18 16:13:30

我喜欢并使用上述解决方案或在数千个文件中进行系统范围的搜索和替换:

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

我假设使用“*.htm?” 它搜索并查找类似的 .htm 和 .html 文件,而不是 .html。

我将 .bak 替换为系统范围内更广泛使用的波形符 (~),以便更轻松地清理备份文件。

I like and used the above solution or a system wide search and replace among thousands of files:

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

I assume with the '*.htm?' instead of .html it searches and finds .htm and .html files alike.

I replace the .bak with the more system wide used tilde (~) to make clean up of backup files easier.

热血少△年 2024-07-18 16:13:30

这可以使用 grep 来完成,而不需要使用 perl 或 find。

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

This works using grep without needing to use perl or find.

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
谎言月老 2024-07-18 16:13:30

<代码>查找 . -type f -print0 | xargs -0将在每批加载一个解释器的同时处理多个包含空格的文件名。 快多了。

find . -type f -print0 | xargs -0 <sed/perl/ruby cmd> will process multiple space contained file names at once loading one interpreter per batch. Much faster.

一指流沙 2024-07-18 16:13:30

的答案

已经给出使用 findsed find -name '*.html' -print -exec sed -i.bak 's/foo/bar/ g' {} \;

可能是标准答案。 或者您可以使用 perl -pi -es/foo/bar/g' 而不是 sed 命令。

对于大多数快速使用,您可能会发现命令 rpl 更容易记住。 这是替换 (foo -> bar),递归地替换当前目录中的所有文件:

rpl -R foo bar 。

默认情况下,大多数 Linux 发行版上不提供该功能,但安装起来很快 (>apt-get install rpl 或类似的)。

然而,对于涉及正则表达式和反向替换、文件重命名以及搜索和替换的更艰巨的工作,我所知道的最通用和最强大的工具是 repren,一个小型 Python 脚本我不久前写过一些棘手的重命名和重构任务。 您可能喜欢它的原因是:

  • 支持文件重命名以及文件内容的搜索和替换(包括在目录之间移动文件和创建新的父目录)。
  • 在承诺执行搜索和替换之前查看更改。
  • 支持正则表达式回退、全字、不区分大小写和保留大小写(替换 foo -> bar、Foo -> Bar、FOO -> BAR)模式。
  • 适用于多个替换,包括交换(foo -> bar 和 bar -> foo)或一组非唯一替换(foo -> bar、f -> x)。

查看自述文件以获取示例。

The answer already given of using find and sed

find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

is probably the standard answer. Or you could use perl -pi -e s/foo/bar/g' instead of the sed command.

For most quick uses, you may find the command rpl is easier to remember. Here is replacement (foo -> bar), recursively on all files in the current directory:

rpl -R foo bar .

It's not available by default on most Linux distros but is quick to install (apt-get install rpl or similar).

However, for tougher jobs that involve regular expressions and back substitution, or file renames as well as search-and-replace, the most general and powerful tool I'm aware of is repren, a small Python script I wrote a while back for some thornier renaming and refactoring tasks. The reasons you might prefer it are:

  • Support renaming of files as well as search-and-replace on file contents (including moving files between directories and creating new parent directories).
  • See changes before you commit to performing the search and replace.
  • Support regular expressions with back substitution, whole words, case insensitive, and case preserving (replace foo -> bar, Foo -> Bar, FOO -> BAR) modes.
  • Works with multiple replacements, including swaps (foo -> bar and bar -> foo) or sets of non-unique replacements (foo -> bar, f -> x).

Check the README for examples.

这实际上比看起来更容易。

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
  • grep 递归遍历你的树 (-R) 并只打印文件名 (-l),从当前目录 (./) 开始,通过
  • 管道传输到 xargs,xargs 一次处理一个文件 (-n 1),并使用% 作为 shell 命令中的占位符 (-I %) (sh -c)
  • 在 shell 命令中,首先打印文件名 (ls %;),
  • 然后 sed 执行内联操作 (-i)、替换('s /') 的 foo 和 bar (foo/bar),在文件上全局 (/g)(同样,用 % 表示)

Easy peasy。 如果您很好地掌握了 find、grep、xargs、sed 和 awk,那么在 bash 中进行文本文件操作几乎没有什么是不可能的:)

This is actually easier than it seems.

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
  • grep recurses through your tree (-R) and prints just the file name (-l), starting at the current directory (./)
  • that gets piped to xargs, which processes them one at a time (-n 1), and uses % as a placeholder (-I %) in a shell command (sh -c)
  • in the shell command, first the file name is printed (ls %;)
  • then sed does an inline operation (-i), a substution('s/') of foo with bar (foo/bar), globally (/g) on the file (again, represented by %)

Easy peasy. If you get a good grasp on find, grep, xargs, sed, and awk, almost nothing is impossible when it comes to text file manipulation in bash :)

暮年慕年 2024-07-18 16:13:30

2022 年答案。
https: //github.com/BurntSushi/ripgrep/blob/master/FAQ.md#how-can-i-search-and-replace-with-ripgrep

rg foo --files-with-matches | xargs sed -i 's/foo/bar/g'

将用 'bar' 替换所有 'foo' 实例ripgrep 在其中找到 foo 模式的文件。 sed 的 -i 标志表示您正在就地编辑文件,而 s/foo/bar/g 表示您正在执行模式 foo 对 bar 的替换,并且您正在全局执行此替换(所有出现的每个文件中的模式)。

2022 answer.
https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#how-can-i-search-and-replace-with-ripgrep

rg foo --files-with-matches | xargs sed -i 's/foo/bar/g'

will replace all instances of 'foo' with 'bar' in the files in which ripgrep finds the foo pattern. The -i flag to sed indicates that you are editing files in place, and s/foo/bar/g says that you are performing a substitution of the pattern foo for bar, and that you are doing this substitution globally (all occurrences of the pattern in each file).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文