起因
代码搜索 / log 分析 / 文本处理,老朋友 grep 一直在。但实际开发场景:
- 项目目录 grep:"grep -r 'foo' ." 默认搜 node_modules / .git → 慢 + 噪音
- 多文件类型:"grep --include='*.py'" 语法不顺
- regex 不一致(POSIX vs PCRE vs Perl)
ripgrep(rg)是 Rust 写的,默认尊重 .gitignore + 多线程 + PCRE2。
工程师日常用比 grep 强百倍。
装
brew install ripgrep
apt install ripgrep
cargo install ripgrep
基础
# 当前目录搜 "foo"
rg foo
# 指定目录
rg foo src/
# 只搜某文件类型
rg foo -t py
rg foo -tpy
# 排除某类型
rg foo -T js
# 列出支持的类型
rg --type-list
默认行为对比 grep
| grep -r | rg | |
|---|---|---|
| 默认递归 | 否(要 -r) | 是 |
| 尊重 .gitignore | 不 | 是 |
| 二进制文件 | 默认搜 | 默认跳过 |
| 隐藏文件 | 默认搜 | 默认跳过(要 --hidden) |
| 多线程 | 否 | 是 |
| Unicode | 不完美 | 完美 |
| 文件名颜色 | 看 alias | 默认彩 |
| 速度 | 1x | 5-100x(看场景) |
在一个 100w 行 / 1 GB / 15k 文件的 monorepo 搜某 function:
$ time grep -r "func MakeWidget" .
real 0m12.345s
$ time rg "func MakeWidget"
real 0m0.143s
差不多 100x(grep 还搜了 node_modules / dist 噪音输出)。
常用 flag
# 上下文
rg foo -A 3 # 后 3 行
rg foo -B 2 # 前 2 行
rg foo -C 5 # 前后各 5 行
# 不区分大小写
rg -i foo
# 完整词
rg -w foo # 不匹配 foobar
# 替换(预览,不写入)
rg foo --replace bar
# 写入:用 sd 或者 rg + xargs
# 列文件名,不显内容
rg foo -l
# 不显文件名(pipeline 用)
rg foo --no-filename
# count
rg foo -c # 每文件 match 数
rg foo --count-matches # 总 match 数
玩 regex
PCRE2 模式:
rg -P 'func\s+(\w+)\s*\(' src/ # 复杂 PCRE
# 多 line(跨行 match)
rg --multiline 'class\s+\w+\s*\{[^}]*\}'
# JSON path-like
rg -P '"name":\s*"\w+"'
PCRE2 (-P) 支持 lookbehind / lookahead / named group。POSIX regex
(-e) 简单但不够。
在 vim / VS Code 用
vim:
" .vimrc
set grepprg=rg\ --vimgrep\ --no-heading
:grep "TODO" " 用 rg 而不是 grep
VS Code:搜索框默认就是 ripgrep(VSCode 内置)。配置可以加 search.useRipgrep
之类(其实默认开)。
配合其它工具
# fzf 实时搜
rg foo | fzf
# fzf preview 找文件 + 高亮内容
rg foo -l | fzf --preview 'rg --color always -n foo {}'
# xargs 批改
rg -l 'oldFunc' | xargs sed -i 's/oldFunc/newFunc/g'
# 或者用 sd(rust sed)
rg -l 'oldFunc' | xargs sd 'oldFunc' 'newFunc'
.ignore + .rgignore
.gitignore ✓ 默认尊重。
项目里加 .ignore 或 .rgignore 文件,让 rg 额外排除:
# .ignore(rg / fd 都用)
generated/
dist/
build/
*.lock
git 不用排但搜索不想看的。
类型自定义
# 注册自定义类型
rg --type-add 'config:*.{yaml,yml,toml,json}'
rg 'redis' -t config
放 alias / config file:
# ~/.config/ripgrep/config
--type-add=config:*.{yaml,yml,toml,json}
--smart-case
--max-columns=200
--max-columns-preview
export RIPGREP_CONFIG_PATH=~/.config/ripgrep/config 让 rg 自动加载。
性能数据
在 Linux kernel source(约 70k 文件,约 1.3 GB):
$ time rg PM_RESUME
0.12s
$ time grep -r PM_RESUME
3.42s
$ time ag PM_RESUME # the_silver_searcher
0.45s
rg 是当前最快的代码搜索工具。
ag / ack 怎么样
ag(the silver searcher):5 年前是黄金标准,今天 rg 全面超越(速度 + 功能)ack:老 perl 写的,速度慢一档rg是事实标准
一个真实工作流
debug 时找"为啥某变量是这值":
# 1. 哪写过这变量
rg "user_score" --type py
# 2. 哪写这值
rg "user_score\s*=" --type py
# 3. 函数调链
rg "calc_user_score|update_user_score" --type py -A 5
# 4. 用 vimgrep 格式给 vim
rg --vimgrep "user_score" --type py > /tmp/grep.out
# 然后 vim -q /tmp/grep.out 跳 quickfix list
10 秒解决"找全部相关代码"。grep 同样要分多次 + 慢 + 噪音。
跟 git grep 对比
git grep 也很快(multi-thread + 知道哪些是 tracked file):
git grep "foo" # 只搜 tracked
git grep -W "foo" # 显示完整函数
优势:知道 git 跟踪状态。
劣势:只搜 tracked,不能搜 untracked / ignored;项目外目录用不了。
我通常 rg 90% + git grep 10%(review 提交时)。
踩过的坑
-
隐藏文件不搜:搜
.env找不到 →rg --hidden。 -
.gitignore 太严:项目里 ignore 了 generated code → rg 也不搜。
rg -uu跳过 ignore;--no-ignore完全不读 .gitignore。 -
PCRE2 没编译:自己编译的 rg 可能没 PCRE2 support →
-P报错。
rg --pcre2-version检查;用 prebuild。 -
大 binary file 误判:rg 用 NUL byte 检测 binary,某些 utf-16
文件被判 binary 跳过。-a强制当文本搜。 -
smart-case 反直觉:默认
--smart-case:全小写 = 不区分大小写;
有大写 = 区分。我有时想要小写也区分大小写 →-s。
登录后参与评论。