grep 命令在 linux 系统中常用于在某个文件目录下查找包含指定目标内容的所有文件。

Vim 作为 linux 系统中最常用的编辑器之一,对外部 grep (或类似 grep) 命令进行了一层封装,提供了 Vim 命令 :grep

使用 :grep 命令,可以在不退出 Vim 的情况下调用 linux 的 grep 命令,实现在多个文件中查找某个模式 (然后可以用 quickfix 列表浏览这些查找结果)。

1. 在 Vim 内部调用grep

假设正在使用 Vim 编辑文本,这时候需要在当前目录的所有文件中查找单词 vim.ink。

最普通的做法是退出 Vim 后在 shell 中执行命令 grep -n vim.ink * (-n 参数指示 grep 在显示结果时加入行号信息)。

但是这么做成本太高,需要在 shell 和 Vim 间来回切换。正如Vim高效率一文所介绍,Vim 对许多日常操作和场景都提供了非常高效的支持。

针对上述场景,Vim 提供了对外部 grep 程序的包装命令 :grep,可以直接在 Vim 中执行 grep 而不用切换到 shell 中执行。在 Vim 的命令行模式下执行命令 :grep vim.ink * 便可以在当前目录的所有文件中查找目标单词 vim.ink

具体来说,Vim 将在后台自动在 shell 终端中执行命令 grep -n vim.ink *,并且 Vim 会对 grep 的输出结果进行解析,再基于解析结果创建一个 quickfix 列表。

:虽然只调用了 :grep vim.ink *,但 Vim 会自动加入 -n 参数指定 grep 命令在输出结果中加入行号信息。

2. 定制 grep 命令

Vim 的 :grep 命令是对外部 grep 程序的封装。类似于Vim定制make编译器介绍的 :make 命令,可以通过配置 grepprggrepformat 选项对 Vim 的查找行为进行定制。

当执行 Vim 的 :grep 命令时,实际上执行的是通过 grepprg 选项指定所调用的外部 shell 程序,而 grepformat 选项则用于指示 Vim 如何解析来自 :grep 命令的输出结果。

在 Unix 系统中,上述两个 Vim 选项的默认设置为:

1
2
grepprg="grep -n $* /dev/null"
grepformat="%f:%l:%m,%f:%l%m,%f %l%m"

出现在 grepprg 选项中的符号 $* 表示占位符,最终将被提供给 :grep 命令的参数所代替。grepformat 选项由一串逗号分隔的字符组成,其内容包括用于解析 :grep 执行结果的符号。其中,%f 表示文件名,%l 表示行号,%m 表示匹配行的文本内容,可通过 :h errorformat 命令查看完整的列表字段介绍。

ack (ack is a tool like grep, optimized for programmers) 是一个比 linux 自带的 grep 效率更高的程序,其官网为 http://betterthangrep.com (better than grep),可见其作者创造它的目的就是为取代grep。ubuntu下要使用命令 sudo apt-get install ack-grep 安装ack,因为在debian系中,ack这个名字被其他的软件占用了。

如果需要使用 ack 代替 Vim 的 :grep命令默认使用的 grep,最简单方法就是对 grepprg 选项进行如下设置:

:set grepprg=ack\ --nogroup\ $*

:上述设置中,空格需要使用 \ 进行转义,-nogroup 参数用于在输出结果中加入行号信息。

3. 使用 Vim 内部的 grep

Vim 提供了一个名为 :vimgrep (缩写形式 :vim) 的命令,其采用的是 Vim 内置的正则表达式查找引擎 (vimgrep 的查找速度远不及grep和ack,毕竟这不是 Vim 的核心能力)。

该命令的语法格式为::vim[grep][!] /{pattern}/[g][j] {file}

g 标志位表示为每个匹配均创建一条记录,否则 Vim 只会为整行文本创建一项记录;缺省情况下,Vim 会直接跳转到第一处匹配,可以通过 j 标志位,让 :vim 命令只更新 quickfix 列表而不跳转到第一处匹配;

参数 {file} 不能为空,接受的参数与 :args 命令的相同,包括文件名、通配符、反引号表达式及它们的组合形式。通配符 * 会匹配目录下的任意文件,通配符 ** 则会匹配指定目录及其子目录中的任意文件,符号 ## 将被扩展成参数列表中的所有文件。

使用 :vimgrep 的主要优点在于它能使用与 Vim查找命令相同的模式。与 :substitute:global 命令类似,如果保持 :vimgrep 命令的模式域为空,:vimgrep 会使用最近一次的查找模式。在实际工作中,一般都是先在当前文件中查找,撰写出符合需求的正则表达式获取到了满意的匹配结果后,就可以使用完全相同的模式来执行 :vimgrep

此外,还可以使用 <Ctrl-r>/ 显式把当前模式的内容粘贴至 :vimgrep 命令的模式域。

vimgrep

嗯,扫一扫就可以找到小女子我啦~