打开由 find … -exec grep … {} \+ 结果给出的文件的可靠方法

打开由 find … -exec grep … {} \+ 结果给出的文件的可靠方法

我经常运行这样的命令:

find … -exec grep … --color=always -l {} \+

有时我需要在 Vim 中打开匹配的文件。

但最可靠的方法是什么?

单程似乎是

vim $(find … -exec grep … {} \+)

另一种方法似乎是利用xargs.

这两种方法以及其他方法(如果有)是否有需要注意的优点/缺点/问题?

答案1

vim $(find path/ -exec grep -l 'pattern' {} +)

是一个不带引号的命令替换,因此将对其结果上的空格执行分词,以及路径名扩展。即,如果文件a b匹配,Vim 将错误地打开a并且b.如果文件* 匹配,唉,它将扩展到相应目录中的每个文件。一个合适的解决方案是

find path/ -type f -exec grep -q 'pattern' {} \; -exec vim {} +

Grep 以quiet 模式运行:每个文件仅使用其返回值。如果0,则在该文件中找到匹配项,并将该文件传递给 Vim。

{} \;表示 Grep 一次分析一个文件。如果我们使用{} +,所有文件都将作为参数传递给 Grep,并且在中找到匹配项任何这些文件的数量将导致0退出状态,因此所有这些文件都将在 Vim 中打开。另一方面,{} +用于 Vim,以便每个找到的文件都进入单个 Vim 进程中的一个缓冲区。您可以尝试更改它们以感受差异。

如果您需要加快速度:

  • 如果'pattern'不是正则表达式,而只是固定模式,则将-F标志添​​加到 Grep 中。

  • grep -lZ、 Xargs 和特殊的 shell 结构也应该会加速这个过程,如果你有的话,请参阅斯特凡·查泽拉斯的回答

这里是 Xargs、Find 和 Vim 的另一个类似用例。

答案2

使用 GNU 工具(您--color=always已经是 GNU 扩展)和支持 Ksh 样式进程替换的 shell:

xargs -r0a <(grep -rlZ pattern .) vim

或者:

xargs -r0a <(find . ... -exec grep -lZ pattern {} +) vim

zsh

vim ${(0)"$(find . ... -exec grep -lZ pattern {} +)"}

4.4+版本bash

readarray -td '' files < <(find . ... -exec grep -lZ pattern {} +)
vim "${files[@]}"

这些最大限度地减少grep了执行的调用次数。要点是告诉grep输出以 NUL 分隔的文件名,这样它们就可以通过vimGNU xargs -0orzsh0参数扩展标志 orbash可靠地分割成单独的参数readarray -td ''

在 中zsh,您还可以执行以下操作:

vim ./**/*(...e['grep -q pattern $REPLY'])

(其中...代表您可能想要添加的进一步限定符,例如find方法)。

然而,这意味着就像使用 的方法一样find -exec grep -q pattern {} ';'grep每个文件将运行一次调用,这会使其速度显着变慢。

zsh如果您将 替换--color=always为并将-Z的值从默认值更改为,则您的第一种方法将起作用。我不会在其他 shell 中工作,因为它们不支持在变量中存储 NUL,更不用说,并且还会对您需要使用或禁用的拆分结果的单词执行文件名生成。IFSIFS=$'\0'IFS=$' \r\n\0'$IFSset -o noglobset -f

为什么循环查找的输出是不好的做法?将为您提供有关如何处理find可靠找到的文件列表的更多提示。

答案3

两种不同的方法:

  1. 将结果放入快速修复列表中:
find ... -exec grep -Hn {} + >results
vim -q results

或者清洁工(但非sh)

vim -q <(find ... -exec grep -Hn {} +)
  1. 使用:grep -R:Cfilter
vim
:grep -R ...
:packadd cfilter
:Cfilter[!]

请参阅相关的:help一些命令。

:cnext无论哪种方式,您都可以使用和其他命令来导航匹配:help quickfix

相关内容