grep 工具大盘点:rg、tgrep、rawgrep、zg

如果你问一个程序员"平时在代码库里怎么找东西",大概率会得到一个答案:rg。ripgrep 从 2016 年发布到现在,快十年了,又快又稳,68k stars,早就成了事实标准。

但你要是追问一句"仓库已经大到 rg 也要扫好几秒,怎么办",答案就变得有看头了。过去一两年,grep 世界冒出来好几路新势力,同一个老问题,各自给了一份不同的答卷:

  • tgrep(微软):预建三元组索引,一次启动、永久秒搜,已经被 Copilot CLI 集成;
  • rawgrep:绕过文件系统,直接读裸盘;
  • zg(阿里 zvec):把 ripgrep、BM25、向量检索捏进一个入口,专门伺候人和 AI Agent。

加上守擂的 rg,这四把刀恰好是四条完全不同的技术路线。挨个拆开看。

先交代一个背景。AI Coding 时代,"搜索"从开发者的日常工具变成了 Agent 的核心基础设施,Agent 找证据靠它、省 token 也靠它。所以这四把刀里有两把(tgrep、zg)几乎就是冲着 AI 编程助手做的。而且更有意思的是,今天主流的几个 Coding Agent,Claude Code、OpenAI Codex、Pi,默认的代码搜索引擎不约而同都选了 ripgrep。这个细节放到第五节说。

一、rg:把"全量扫描"做到极致

rg 的思路简单粗暴:把每个文件从头到尾读一遍,用 SIMD 加速的 regex 引擎去匹配。这一派的全部本事,都押在"单位时间能扫多少字节"上。

为了跑赢这个目标,rg 做了几件事:

  • 默认递归 + 自动过滤:gitignore、隐藏文件、二进制文件默认全跳过,rg -uuu 才彻底放开;
  • Unicode 默认开启且不掉速:GNU grep 到现在都做不到这点,rg 是"一直开着 Unicode 还最快";
  • 类型过滤:rg -tpy foo 只搜 Python 文件,rg -Tjs foo 排除 JS,还能自定义类型;
  • PCRE2 可选:-P 切到回溯引擎,前瞻、反向引用都能用,平时不用则默认引擎保持快;
  • 搜压缩文件:-z 直接搜 gzip、xz、bzip2 等;
  • 预处理器管道:可以把 PDF 抽取成文本再搜;
  • 编码支持:UTF-16、GBK、Shift_JIS 等都能指定。

性能上,它 README 里的 benchmark 一直是别的工具拿来"仰望"的:Linux 内核源码搜 [A-Z]+_SUSPEND 只要 0.082s(i9-12900K,rg 官方 README 数据),比 ag 快 5 倍,比 ack、git grep 快 30 多倍。

一次搜索的耗时,和"所有被搜文件的总字节数"成正比(也就是 O(n),n 是总字节数)。rg 不建索引、不缓存,它搜索之前并不知道哪些文件可能命中,只能把范围内的每个文件从头到尾读一遍去匹配。所以搜 1GB 的仓库是搜 100MB 仓库的 10 倍耗时,跟模式多简单没关系。

二、tgrep:换赛道,先建索引,只碰候选文件

微软的 tgrep 直接换了个思路:不做全扫,而是预建三元组(trigram)索引,搜索时只碰那些"可能命中"的文件。它的口号很拽:

Start a server once, search instantly forever.

用法就三句话:

它采用server/client的架构。

效果有多夸张,看它 README 里的 benchmark。gecko-dev 这个 388K 文件的仓库,macOS 上 ripgrep 一次搜索要 33.4 秒,tgrep 只要 643 毫秒,51.9 倍。chromium 504K 文件是 15.8 倍,Linux 内核 21 倍。18 个测试格子里,tgrep 赢了 17 个。

它已经被 GitHub Copilot CLI 集成进去,给 AI 编程助手做超大仓库的代码搜索。能被 Copilot 挑中,这条路线本身就被大规模验证过了。

架构上有几个点值得说:

  • 双层索引:IndexReader(磁盘上 mmap 的索引,零拷贝、二分查找)+ LiveIndex(内存覆盖层,处理 server 启动后新改的文件),查询时两层合并,overlay 优先;
  • 后台并行建索引(rayon,每批 1024 个文件),没建完之前查询先退回文件系统扫描,不会让你干等;
  • 周期落盘:每 5 分钟或每 5 万个文件,把内存索引刷到磁盘并换读端,内存有界;
  • 内存有界建索引:默认 external 策略,用外部归并排序把峰值内存压到 160MB,同样一个索引纯内存态要 23.6GB,降了 17 倍还不掉速。

适合什么场景?超大 monorepo + 同一个仓库被搜很多次。索引成本摊得越薄越赚。如果只是偶尔 grep 一下的小项目,建索引的功夫可能比直接扫还贵,不过 tgrep 留了 --no-index,随时退回全扫。

两个使用上的坑,README 里特意强调过:

  1. tgrep index 和 tgrep serve 的参数(比如 --max-filesize、--exclude)必须保持一致,不然 server 会把超过限额的索引文件当成"已删除";
  2. .gitignore 只在 git 仓库里生效(和 rg 一致),非 git 目录要显式加 --no-require-git,否则索引会比你预期的大很多。

三、rawgrep:物理外挂,直接读裸盘

如果说 tgrep 是"换算法",那 rawgrep 是"换介质"。它压根不走文件系统,直接读裸块设备。口号是 Grep at the speed of raw disk。

/dev/sda1 归内核管,所以要读它,要么每次 sudo,要么用 Linux capability 只授 cap_dac_read_search 这一个能力。

它快的关键有两点:

  1. 绕过文件系统,直接流式读设备,少一层开销;
  2. fragment cache:一个基于"片段"的缓存(灵感来自 nowgrep),会"学习"哪些文件在重复搜索中可以跳过。搜索越大越勤,这个缓存越值钱。

Chromium 500K 文件的语料上搜 TODO:热缓存 + fragment cache 是 131.8ms,rg 是 363.5ms(2.76 倍);冷缓存下 2.72s vs 11.90s(4.38 倍)。大语料优势更明显,作者在自己 127 万个文件的 home 目录上跑出过 ~60 倍。

但代价也很实在,作者在 README 里全摊开了:

  • 只有 Linux,且要求 ext4/ntfs 文件系统,macOS、Windows 直接劝退;
  • 需要 root 或 setcap 能力,给二进制授绕过读权限的能力,很多人不敢也不该碰;
  • 内存占用还没优化好,作者自己吐槽 RSS 偏高,目前一门心思扑在"快"上。

说白了,这是个很酷的技术玩具,加上少量特定场景(只读分区、超大日志、要反复搜的超大盘)是真利器。但对绝大多数开发者,"读裸盘"这四个字就把门槛焊死了。日常大概率用不上,但值得知道它的存在,它算是"grep 性能天花板"的一个参照系。

四、zg:把语义搜索塞进 grep,专门伺候 AI Agent

前三个都还在解决"正则匹配怎么更快",zg(zvec-grep)直接跳出关键词的框:把 ripgrep + BM25 + 向量检索统一在一个本地优先的入口后面。

它的定位很简单:先按意思找东西,再按关键词验证。先用语义召回相关片段、按相关性排序,需要精确确认时再落到文本或正则。支持源码、文档、结构化数据多格式检索,结果保留结构和来源位置。

跟前面几个工具比,它有两个很不一样的地方。

一个是"本地优先"不是口号。文件、索引、本地模型全在本机,远程 embedding 只有你授权才会上传数据。对代码这种敏感数据,这个默认值很重要。

另一个是它天生为 Agent 设计。有 MCP 支持,能接 Codex、Claude Code、Qwen Code、Cursor、OpenCode。它的 benchmark 也是拿 Agent 跑的:SWE-QA-Bench 用 Claude Code + Opus,BrowseComp-Plus 用 Codex,比的是"回答质量、输入 token、工具调用次数、耗时",而不是单纯的手速。结论很对我的胃口:语义召回能显著减少 Agent 的无效搜索和 token 消耗。

作者是阿里的 zvec 团队,README 中英双语,社区直接放钉钉、微信群、Discord 二维码,少见地接地气,交流起来方便。

五、Claude Code、Codex、Pi:Coding Agent 现在都用啥搜代码

前面说"搜索是 Agent 的核心基础设施",那今天的头部 Coding Agent 到底用什么工具搜代码?我把它们的实现翻了一遍,结论意外地统一:全是 ripgrep。

  • Claude Code:内置的 Grep 工具底层就是 ripgrep,而且直接捆绑在发行版里,不用你机器上装了 rg,装好 Claude Code 就自带,跨平台行为一致。默认并行搜索,正则语义和 rg 完全一致。
  • Codex(OpenAI):更干脆。它的打包脚本里有一句硬要求,"ripgrep is required for all package targets",意思是每个平台的发行版都必须带上 rg。所以 Codex 沙箱里的代码搜索,用的就是这个捆绑好的 ripgrep,不用管目标机器装没装。
  • Pi(earendil-works/pi):内置工具清单里就有 grep 和 find。它那个 grep 工具的实现,是 spawn 一个 rg 进程,传上 --json --line-number --color=never --hidden 这套参数,再解析 ripgrep 的 JSON 输出。如果机器上没有 rg,还会自动帮你下载一个。

三家不同阵营的 Coding Agent,底层都选了同一个引擎:ripgrep。原因不难理解:对 Agent 来说,"搜代码"这个动作不能出错、不能慢,而 ripgrep 是那个经过十年验证、默认行为合理(尊重 gitignore、跳过二进制)、输出格式好解析(--json)的默认答案。Agent 的第一搜,都是 rg。

这也正好解释了前面那两把新刀存在的意义。rg 是 Agent 的默认,但当仓库大到 rg 也要扫好几秒时,tgrep 用索引把"每次全扫"变成"只碰候选文件",zg 用语义召回减少 Agent 的无效搜索和 token 消耗。它们都是在"rg 这个默认答案"之上继续卷。

六、怎么选:一张表

工具思路实现平台适合场景上手成本
rg全扫派:算法足够快Rust全平台日常一切 grep极低,安装即用
tgrep索引派:预建三元组Rust全平台超大 monorepo、高频重复搜中,先建索引
rawgrep裸盘派:绕过文件系统Rust仅 Linux只读分区、超大日志高,需 root/能力
zg语义派:向量 + BM25 + rgTypeScript全平台AI Agent、语义检索中,需 Node 22+
几个朴素建议:
  • 如果只是日常写代码找东西,rg 永远是默认,别折腾,稳如老狗。
  • 如果仓库大到 rg 一次要等好几秒,而且你(或你的 AI)一天要搜几十次,tgrep 值得上,索引成本早就摊回来了。Copilot CLI 都选它了,说明是被验证过的路线。
  • rawgrep 适合当性能天花板来看,真要用得先确认自己接受"Linux + 能力"的门槛。
  • 如果你在用 AI Coding Agent,且受够了它在一堆无关代码里瞎翻、白白烧 token,zg 是值得关注的那个。语义 + 关键词的组合拳,正好补上纯 grep 在"不知道确切名字"时抓瞎的短板。

最后说一句。这四把刀并排放一起,是个挺有意思的切面:同一个"找东西"的问题,有人押算法,有人押索引,有人押硬件,有人押语义。你按自己的场景挑一把顺手的就行,不用纠结谁是最强的。

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论