ripgrep:比 grep 快 10 倍的代码搜索神器


在日常开发中,全局搜索代码几乎是我们每天重复几十上百次的操作。当你敲下 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

七、工具对比

对比维度grepripgrepag (The Silver Searcher)
底层语言CRustC
适用场景搜单个日志文件 / 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 绝对是重塑生产力的神器。

参考资源

← 返回博客