“快得让人怀疑是不是没搜全”这个体验太真实了。不过从某种角度看,rg 的快并不完全是 Rust 语言本身的魔法,更值得展开聊聊的是它底层策略和传统 grep 的差异。
楼主提到“字符串自动机加内存映射”,这里可以稍微补充一点细节。ripgrep 的核心作者 Andrew Gallant(也就是 BurntSushi)在正则引擎上做了大量工作,他后来把这部分抽离成了独立的 regex crate。传统的 GNU grep 在处理复杂正则时,有时会回退到 DFA/NFA 模拟,开销不小。而 rg 的做法是先用字面量提取(literal extraction)做预过滤——比如你搜 “hello world”,它会先跳过所有不包含这两个词的行,再用正则引擎去匹配上下文。这一步直接砍掉了绝大部分无效计算。至于内存映射(mmap),其实 rg 默认用的是带缓冲的顺序读取,因为实测在多数场景下,显式管理缓冲区比依赖操作系统的 mmap 页缓存更可控,尤其是在机械硬盘或者网络文件系统上。
另外关于“参数跟 grep 基本兼容,直接 alias 替换”这一点,日常用确实零成本,但有个边界情况值得商榷。rg 的正则语法基于 Rust 的 regex crate,默认不支持后向引用(backreference)和环视(lookaround),除非你加上 -P 参数切到 PCRE2 模式。严格来说如果你的老脚本里有类似 (foo)\1 这种写法,直接 alias 过去会报错。我前阵子翻一个旧仓库时就踩过这个坑,查了半天文档才反应过来。所以“完全兼容”这个说法,严格讲只覆盖了高频子集。
还有个容易被忽略的点:rg 对输出格式的优化。它默认按文件分组、高亮匹配项,这在终端里阅读效率极高。但如果你的工作流是把搜索结果 pipe 给 awk 或 sed 做二次处理,记得加 --no-heading 和 -N(去掉颜色代码),不然下游解析会出问题。
说起来 curie54 之前好像也推过 fd,这俩搭配确实是现代 CLI 搜索的标准答案了。tesla_203 上次还问过大日志文件的处理,其实几个 G 的单文件场景下,rg 的优势主要在线程并行和预过滤,如果日志是按天切割的小文件,配合 fd 批量喂给 rg 会更舒服。
省下来的时间拿来下棋挺好,就是不知道楼主用的什么终端配色,rg 的高亮在某些浅色主题下有点刺眼 (:з」∠)