Enl*_*ico 5 grep vim find xargs
我经常运行这样的命令:
find … -exec grep … --color=always -l {} \+
Run Code Online (Sandbox Code Playgroud)
有时我需要在 Vim 中打开匹配的文件。
但最可靠的方法是什么?
一种方法似乎是
vim $(find … -exec grep … {} \+)
Run Code Online (Sandbox Code Playgroud)
另一种方法似乎是利用xargs.
这两种方法和其他方法(如果有的话)是否有优点/缺点/问题需要注意?
Qua*_*odo 13
vim $(find path/ -exec grep -l 'pattern' {} +)
Run Code Online (Sandbox Code Playgroud)
是一个不带引号的命令替换,因此将对其结果的空格以及路径名扩展进行分词。即,如果文件a b匹配,Vim 将错误地打开a和b. 如果文件*
匹配,唉,它将被扩展到相应目录中的每个文件。一个合适的解决方案是
find path/ -type f -exec grep -q 'pattern' {} \; -exec vim {} +
Run Code Online (Sandbox Code Playgroud)
Grep 在quiet 模式下运行:每个文件只使用它的返回值。如果0,则在该文件中找到匹配项并将该文件传递给 Vim。
{} \;意味着 Grep 将一次分析一个文件。如果我们使用{} +,则所有文件都将作为参数传递给 Grep,并且在这些文件中的任何一个中找到匹配项都会导致0退出状态,因此所有这些文件都将在 Vim 中打开。另一方面,{} +用于 Vim 以便它在单个 Vim 进程中每个找到的文件都进入一个缓冲区。您可以尝试更改它们以感受不同。
如果您需要加快速度:
如果'pattern'不是正则表达式,而只是固定模式,则将-F标志添加到 Grep。
grep -lZ, Xargs 和特殊的 shell 结构也应该加快这个过程,如果你有的话,请参阅Stéphane Chazelas 的回答。
而这里是另一个类似用途例xargs的,查找和Vim。
使用 GNU 工具(您--color=always已经是 GNU 扩展)和支持 Ksh 样式进程替换的 shell:
xargs -r0a <(grep -rlZ pattern .) vim
Run Code Online (Sandbox Code Playgroud)
或者:
xargs -r0a <(find . ... -exec grep -lZ pattern {} +) vim
Run Code Online (Sandbox Code Playgroud)
与zsh:
vim ${(0)"$(find . ... -exec grep -lZ pattern {} +)"}
Run Code Online (Sandbox Code Playgroud)
使用bash4.4+:
readarray -td '' files < <(find . ... -exec grep -lZ pattern {} +)
vim "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
这些最大限度地减少了grep执行的调用次数。关键是要告诉grep输出以 NUL 分隔的文件名,因此它们可以被vimGNU xargs -0orzsh的0参数扩展标志或bash's可靠地拆分为单独的参数readarray -td ''。
在 中zsh,您还可以执行以下操作:
vim ./**/*(...e['grep -q pattern $REPLY'])
Run Code Online (Sandbox Code Playgroud)
( where...代表您可能想要添加的更多限定符,例如find方法)。
然而,这意味着就像使用 的方法一样find -exec grep -q pattern {} ';',grep每个文件都会运行一次调用,这会使其速度明显变慢。
在你的第一个方法是有效的zsh提供您更换--color=always同-Z和改变的值IFS,以IFS=$'\0'从默认的IFS=$' \r\n\0'。我不会在其他 shell 中工作,因为它们不支持将 NUL 存储在变量中,更不用说$IFS并且还会对您需要使用set -o noglob或禁用的拆分结果的单词执行文件名生成set -f。
为什么循环查找的输出是不好的做法?将为您提供有关如何处理find可靠找到的文件列表的更多提示。