ripgrep(rg):为什么我把 grep 完全弃了

起因

代码搜索 / log 分析 / 文本处理,老朋友 grep 一直在。但实际开发场景:

  • 项目目录 grep:"grep -r 'foo' ." 默认搜 node_modules / .git → 慢 + 噪音
  • 多文件类型:"grep --include='*.py'" 语法不顺
  • regex 不一致(POSIX vs PCRE vs Perl)

ripgreprg)是 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 提交时)。

踩过的坑

  1. 隐藏文件不搜:搜 .env 找不到 → rg --hidden

  2. .gitignore 太严:项目里 ignore 了 generated code → rg 也不搜。
    rg -uu 跳过 ignore;--no-ignore 完全不读 .gitignore。

  3. PCRE2 没编译:自己编译的 rg 可能没 PCRE2 support → -P 报错。
    rg --pcre2-version 检查;用 prebuild。

  4. 大 binary file 误判:rg 用 NUL byte 检测 binary,某些 utf-16
    文件被判 binary 跳过。-a 强制当文本搜。

  5. smart-case 反直觉:默认 --smart-case:全小写 = 不区分大小写;
    有大写 = 区分。我有时想要小写也区分大小写 → -s

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。