Linux vimgrep 详解
简介
- 
与外部
grep不同,vimgrep在查到结果后会将匹配行写入 快速修复列表(quickfix list),并可通过:copen、:cnext、:cfirst等命令逐条跳转 - 
支持
Vim的正则引擎,允许灵活使用Vim正则、分组、魔法模式等 
基本语法
:vimgrep[!] /{pattern}/[g][j] {file_pattern}[ ...]
- 
!:表示清空当前quickfix列表;不带!时会追加到现有列表 - 
/…/:Vim正则模式,若包含/,可改用其它分隔符,如#…# - 
g:对匹配到多处的行,依然只在列表中记录一次;不加g时同一行多次匹配会重复记录 - 
j:匹配后不跳转到第一个结果,仅更新列表不移动光标 - 
{file_pattern}:文件通配符,支持*,**(递归)、?等 
例 1:搜索当前目录下所有 .c 文件中包含 “TODO” 的行
:vimgrep /TODO/ *.c
- 执行后,打开 
quickfix列表: 
:copen
- 跳到下一个匹配:
 
:cnext
- 跳到上一个匹配:
 
:cprevious
文件搜索范围示例
:vimgrep /error/ %% 表示当前缓冲区:vimgrep /TODO/ *.txt.txt 文件:vimgrep /function_name/ **/*.py:vimgrep /pattern/ file1.txt file2.txt:vimgrep /pattern/ **/*.cpp **/*.h:vimgrep /pattern/ ##核心用法示例
基础搜索(当前目录指定文件)
:vimgrep \"error\" *.log \" 在当前目录所有.log文件中搜索\"error\"
递归搜索(包含子目录)
使用 ** 匹配所有子目录:
:vimgrep \"func\"**/*.py \" 在所有子目录的.py文件中搜索\"func\"
正则表达式搜索
支持 Vim 风格正则(如 \\d 匹配数字,\\w 匹配单词字符):
:vimgrep \"age=\\d+\" **/*.html \" 搜索所有html中\"age=数字\"的模式
区分大小写 / 忽略大小写
- 
默认区分大小写
 - 
加
i参数忽略大小写: 
:vimgrep /Error/ig **/*.js \" i = 忽略大小写,g = 全局匹配(每个文件找所有匹配)
结合快速修复列表(Quickfix)
- 打开列表
 
:copen \" 在窗口下方打开 quickfix 窗口:cclose \" 关闭 quickfix 窗口
- 在列表中跳转
 
:cfirst \" 跳到第一个匹配:clast \" 跳到最后一个匹配:cnext \" 下一个:cprevious\" 上一个:cc [nr] \" 跳到第 nr 条(不带 nr 跳到下一条) 
- 在列表中执行批量操作
 
比如对所有匹配行做修改,可配合 :cfdo
:cfdo s/old/new/ge | update
这会对 quickfix 中的每个文件执行替换并保存。
- 快捷键映射(加入 
~/.vimrc提升效率): 
nnoremap <F8> :copen<CR> \" F8 打开 Quickfixnnoremap  :cclose \" F9 关闭nnoremap <F10> :cnext<CR> \" F10 下一项nnoremap  :cprev \" F11 上一项
常用选项和技巧
- 只列出文件名
 
:vimgrep /pattern/ **/*.py | cw
然后在 quickfix 窗口里可以只关注文件名列。
- 使用非常规分隔符
 
当搜索模式里包含 / 时,用其它符号:
:vimgrep #{foo/bar}# **/*.js
- 只更新列表、不跳转
 
:vimgrep j /TODO/ **/*.java
搜索后光标不动,便于接着做别的。
- 区分大小写
 
Vim 默认受 ignorecase 和 smartcase 影响,你可临时加 \\C 强制大小写敏感,或 \\c 强制忽略大小写:
:vimgrep /\\CError/ **/*.log
- 与 
:args/argdo配合 
先加载参数列表:
:args **/*.md
再 vimgrep 并跳转:
:vimgrep /TODO/ % | copen
高级技巧与性能优化
结合通配符精确筛选文件
:vimgrep \"config\" **/*.{json,yml} \" 搜索所有子目录的.json和.yml文件
将结果保存到文件
:vimgrep \"todo\"**/*.php | :cwrite todo_list.txt \" 搜索结果保存到todo_list.txt
批量替换搜索结果
结合 cdo 命令(对快速修复列表中的每个文件执行命令):
:vimgrep \"old_str\" **/*.py \" 先搜索目标字符串:cdo %s/old_str/new_str/g | w \" 对所有匹配文件执行替换并保存
自定义快捷键
在 .vimrc 中配置快捷键,简化操作:
nnoremap <leader>vg :vimgrep // **/*.<C-R>=expand(\'%:e\')<CR><Left><Left>
按 vg 后,自动填充当前文件类型的搜索模板,直接输入关键词即可
限制搜索范围
\" 只在修改过的文件中搜索:vimgrep /warning/ `bufname()` \" 当前缓冲区:vimgrep /bug/ `expand(\'%:p:h\')/*.c` \" 当前目录
性能优化
\" 忽略大目录(如 node_modules):set wildignore+=*/node_modules/*:vimgrep /pattern/ **/*.js \" 自动跳过忽略目录
正则表达式转义
Vim 的正则语法与 Perl/PCRE 不同,需注意 \\v(非常魔术模式)简化语法。
:vimgrep /\\v<word>/ *.txt
多文件编辑:
结合 :argdo 或 :bufdo 进行批量操作
:argadd *.c:argdo vimgrepadd /TODO/ % | cdo s/TODO/DONE/g | update
添加全局忽略配置
修改 .vimrc 文件
set wildignore+=*.o,*.obj,.git
lvimgrep 替代方案
使用 :lvimgrep 将结果存入 Location List(窗口局部列表),适用于多窗口并行搜索:
:lvimgrep /warning/ **/*.log :lopen \" 打开 Location List:lnext 
加速 vimgrep 性能
- 
问题:
vimgrep需模拟打开每个文件,大项目较慢 - 
优化:
- 使用 
:noautocmd跳过插件/事件干扰: 
:noautocmd vimgrep /pattern/ **/*.js- 换用外部 
grep(需配置): 
:set grepprg=grep\\ -nri\\ --include=*.{c,h} 定义外部 grep 参数:grep \"function_name\" . 调用外部 grep - 使用 
 
区别::vimgrep vs :grep
:vimgrep:grep:grepprg 设置或 :make 设置才可输出如果更喜欢 rg、ag 的速度并想结合 quickfix,只需在 .vimrc 中:
set grepprg=rg\\ --vimgrep\\ --no-heading\\ --smart-caseset grepformat=%f:%l:%c:%m
这样用 :grep 就等同于 :vimgrep 加速版。
进阶:批量替换与脚本化
全项目批量替换
:vimgrep /foo()/ **/*.cpp:cfdo %s/foo()/bar()/g | update
在 Vim 脚本中使用
function! ReplaceInProject(pat, rep) execute \'vimgrep /\'.a:pat.\'/j **/*.js\' copen execute \'cfdo %s/\'.a:pat.\'/\'.a:rep.\'/g | update\' ccloseendfunction\" 用法::call ReplaceInProject(\'oldFunc\', \'newFunc\')
实战示例
案例 1:项目级重构
\" 查找所有使用旧 API 的地方:vimgrep /\\/ **/*.c:copen \" 查看结果并手动验证:cfdo %s/old_api_call/new_api_call/g | update
案例 2:日志分析
\" 在所有日志中提取 ERROR 行:vimgrep /^$$ERROR$$/ /var/log/*.log:copen\" 在 quickfix 窗口按 : 输入::cfdo g/^$$ERROR$$/yank A | put! A 将所有错误复制到新缓冲区


