在日常开发中,全局搜索代码几乎是我们每天重复几十上百次的操作。当你敲下 grep -r "myFunction" .,终端卡住、CPU 狂飙,等了半天出来的全是 node_modules 里的第三方依赖、.git 历史版本或编译生成的二进制文件——这正是传统 grep 在现代大型代码仓库中的典型困境。ripgrep(命令为 rg)就是为解决这些痛点而生,如今 VS Code、Cursor、Zed 等现代编辑器的全局搜索底层都已悄然换成了它。
一、传统 grep 的痛点
grep 作为 Linux/Unix 时代的基石工具无疑是伟大的,处理单个日志文件、配合管道符过滤信息(如 cat app.log | grep ERROR)时效率依然顶尖。但在现代大型代码仓库中,它的劣势非常明显:
- 盲目搜索:grep 默认不会避开
.gitignore、隐藏目录或二进制文件,必须手动拼写长串参数(如--exclude-dir)来排除干扰。 - 默认单线程遍历:面对包含几万个文件的项目,逐个文件单线程扫描瓶颈极其明显。
- 终端呈现朴素:默认输出可读性较差,需要手动加
--color,且结果不会按文件分组展示。
二、ripgrep 的核心优势
ripgrep 由 BurntSushi(Andrew Gallant)用 Rust 开发,从设计之初就为了给开发者提供极致的代码搜索体验。它的四大杀手锏如下:
智能过滤
ripgrep 默认开启开箱即用的智能忽略:
- 自动识别并尊重项目的
.gitignore、.ignore和.rgignore。 - 默认跳过隐藏文件和二进制文件,避免终端被乱码刷屏。
- 默认跳过软链接,防止死循环。
这意味着直接敲 rg "myFunction",它只会搜索你真正关心的源码,天然省去约 90% 的无效 I/O。
极速搜索
在多核 CPU 普及的今天,ripgrep 将 Rust 的并发优势发挥到了极致:
- 多线程并行遍历:自动根据物理 CPU 核心数启动多线程并行检索。
- SIMD 与内存映射:利用现代 CPU 的 SIMD 指令集加快字节匹配,并使用 Memory Mapping(mmap)优化大文件读取。
- 高效正则引擎:内部使用 Rust 的
regex库,通过构造自动机(DFA)保证搜索时间复杂度稳定,杜绝回溯导致的卡死。
舒适的终端体验
在终端直接使用 rg 时,结果会自动按文件路径分组,清晰标注行号,并高亮匹配到的关键词:
src/services/user.ts
12: export async function getUserInfo(id: string) {
45: const info = await fetchUserInfo(id);
src/controllers/auth.ts
88: const user = await getUserInfo(req.params.id);
全平台与多编码支持
不管是 Linux、macOS 还是 Windows,ripgrep 都有完美的原生支持。并且它能自动检测 UTF-8、UTF-16、GBK、Shift_JIS 等多种文本编码,不用担心乱码问题。
三、安装方法
macOS
# 使用 Homebrew
brew install ripgrep
Linux
# Debian/Ubuntu
sudo apt install ripgrep
# Arch Linux
sudo pacman -S ripgrep
# Fedora
sudo dnf install ripgrep
Windows
# 使用 Scoop
scoop install ripgrep
# 使用 Chocolatey
choco install ripgrep
其他方式
# 使用 cargo(Rust 包管理器)
cargo install ripgrep
也可以从 GitHub Releases 下载预编译二进制文件。
四、基本用法
最简单的搜索
# 在当前目录及其子目录中搜索 "function"
rg function
# 搜索特定文件
rg function src/main.js
# 搜索特定目录
rg function src/
常用选项
| 选项 | 作用 | 示例 |
|---|---|---|
-i | 忽略大小写 | rg -i apperror |
-w | 全词匹配 | rg -w function |
-l | 只显示匹配的文件名 | rg -l function |
-c | 显示匹配次数 | rg -c function |
-n | 显示行号 | rg -n function |
-C N | 显示上下文(前后各 N 行) | rg -C 3 function |
-B N | 显示前 N 行 | rg -B 3 function |
-A N | 显示后 N 行 | rg -A 3 function |
正则表达式
# 基本正则
rg "func.*name"
# 或操作
rg "function|class"
# 匹配数字
rg "\d{3,4}"
# 匹配邮箱
rg "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"
五、高级技巧
文件类型过滤
# 只在特定文件类型中搜索
rg -t js function # JavaScript 文件
rg -t py function # Python 文件
rg -t rs function # Rust 文件
# 排除特定文件类型
rg -T md function # 排除 Markdown 文件
# 指定扩展名
rg -g "*.js" function
rg -g "*.{js,ts}" function
# 排除特定模式
rg -g "!node_modules" function
rg -g "!*.min.js" function
搜索替换
ripgrep 支持在不修改原文件的前提下预览替换结果:
# 输出替换后的内容到终端(不修改原文件)
rg function --replace method
# 只显示替换后的匹配部分
rg function --replace method --only-matching
颜色与格式
# 禁用颜色
rg --color never function
# 强制颜色(适用于管道)
rg --color always function | less -R
# 自定义颜色
rg --colors "match:fg:red" function
搜索隐藏文件与被忽略文件
# 搜索隐藏文件或被 .gitignore 忽略的文件
rg -u "SECRET_KEY"
# 强制搜索被 gitignore 的文件
rg --no-ignore-vcs function
# 强制搜索二进制文件
rg --text "pattern" binary_file
六、实战案例
查找函数定义
# JavaScript/TypeScript 函数定义
rg "function\s+\w+" -t js
rg "const\s+\w+\s*=\s*\(" -t js
# Python 函数定义
rg "^def\s+\w+" -t py
查找导入语句
# JavaScript import
rg "^import\s+" -t js
# Python import
rg "^import\s+|^from\s+" -t py
查找 TODO/FIXME 注释
rg -i "TODO|FIXME|XXX|HACK"
查找调试语句
# JavaScript console.log
rg "console\.(log|debug|warn|error)" -t js
# Python print
rg "^\s*print\(" -t py
统计代码行数
# 统计所有 JavaScript 文件的总匹配数
rg -t js --count-matches | awk -F: '{s+=$2} END {print s}'
# 按文件统计匹配数并排序
rg -c function | sort -t: -k2 -rn
与其他工具组合
# 与 fzf 组合(交互式搜索)
rg --files | fzf
# 与 xargs 组合(批量操作)
rg -l "console.log" -t js | xargs sed -i '' '/console.log/d'
# 与 less 组合(分页查看)
rg function | less -R
# 输出到文件
rg function > results.txt
七、工具对比
| 对比维度 | grep | ripgrep | ag (The Silver Searcher) |
|---|---|---|---|
| 底层语言 | C | Rust | C |
| 适用场景 | 搜单个日志文件 / Server 脚本 | 搜大型代码仓库 / 终端交互 | 搜代码仓库 |
| .gitignore 支持 | 需手动配规则 | 默认自动跳过 | 默认支持 |
| 并行计算 | 默认单线程 | 默认多线程 | 默认多线程 |
| 终端展示 | 朴素,无默认分组 | 按文件分组 + 高亮行号 | 按文件分组 |
| Windows 原生支持 | 支持 | 支持 | 不支持 |
| 正则引擎 | 部分支持 | 支持 PCRE2 | 部分支持 |
| 预装情况 | Unix/Linux 自带 | 需单独安装 | 需单独安装 |
八、配置与集成
别名设置
在 .zshrc 或 .bashrc 中添加常用别名:
# 常用别名
alias rg='rg --smart-case'
alias rgi='rg -i' # 忽略大小写
alias rgl='rg -l' # 只显示文件名
alias rgn='rg -n' # 显示行号
alias rgc='rg -C 3' # 显示上下文
alias rgt='rg -t js' # 搜索 JS 文件
环境变量配置
# 指定配置文件路径
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
.ripgreprc 示例:
--smart-case
--hidden
--glob=!*.min.js
--glob=!node_modules/
使用 .rgignore
在项目根目录创建 .rgignore 文件来排除不需要搜索的目录:
node_modules/
dist/
build/
*.min.js
*.min.css
coverage/
.vscode/
.idea/
编辑器集成
VS Code:内置搜索默认使用 ripgrep(如果系统已安装),无需额外配置。
Vim/Neovim:
" 使用 ripgrep
command! -nargs=+ Rg execute 'Grepper! -tool rg -query <q-args>'
" 或配合 fzf.vim
:Rg function
九、常见问题 FAQ
ripgrep 和 grep 有什么区别?什么时候该用哪个?
ripgrep(rg)专门为现代代码仓库搜索设计,默认自动忽略 .gitignore 中的文件、隐藏文件和二进制文件,采用多线程并行搜索,速度比 grep 快 5-10 倍;输出默认带高亮、行号、按文件分组,可读性更好。grep 是 POSIX 标准工具,几乎所有 Unix/Linux 系统都预装,适合编写通用 Shell 脚本或在没有安装 ripgrep 的服务器上使用。日常开发搜索代码推荐用 ripgrep,写可移植脚本时用 grep。
ripgrep 命令为什么叫 rg?
rg 是 ripgrep 的标准命令行别名,安装后输入 rg 即可调用,比输入完整名称 ripgrep 更方便快捷,类似 grep 就叫 grep。
ripgrep 可以搜索替换吗?
ripgrep 本身支持 --replace 参数预览替换结果,但不会直接修改原文件。如果需要批量替换,可以配合 sed 或使用专门的替换工具如 sd,命令示例:rg -l "old" | xargs sed -i '' 's/old/new/g'。
为什么 ripgrep 默认不搜索 node_modules?
ripgrep 默认会读取项目根目录的 .gitignore 文件,自动忽略其中列出的目录和文件,node_modules 通常在 .gitignore 中,所以默认不会搜索。如果你需要强制搜索,可以使用 -u 参数或添加 --no-ignore。
ripgrep 支持 PCRE 正则吗?
是的,ripgrep 默认使用 Rust 的正则引擎,支持大部分 PCRE 特性,使用 -P 或 --pcre2 参数可以启用完整的 PCRE2 正则支持(需要编译时启用)。
VS Code 真的是用 ripgrep 做全局搜索吗?
是的,VS Code 从很早的版本开始就内置了 ripgrep 作为全局搜索的底层引擎,这也是为什么 VS Code 在大型项目中搜索速度依然很快的原因之一。Cursor、Zed 等基于 VS Code 或现代架构的编辑器同样使用 ripgrep。
十、总结
ripgrep 是现代开发者的必备工具之一,它快、省时、易用、功能强。一旦开始使用,就很难回到传统的 grep 了。记住几个常用选项(-i、-l、-t、-C),就能覆盖 90% 的搜索场景。
当然,如果你在写通用的 Shell 脚本,或者要在没有任何外部依赖的干净服务器上跑管道,grep 依然是不可替代的通用标准。但在本地拉取大型源码库时,ripgrep 绝对是重塑生产力的神器。