ripgrep:把"在仓库里找代码"变成一条命令的事
【免费下载链接】ripgrepripgrep recursively searches directories for a regex pattern while respecting your gitignore项目地址: https://gitcode.com/GitHub_Trending/ri/ripgrep
如果你在终端里敲过grep -r "TODO" .,大概率经历过这样的场景:结果被node_modules和构建产物刷屏、二进制文件把终端搞乱、中文路径乱码,最后还得手动加一堆参数。ripgrep(命令行里叫rg)就是为了解决这类问题而生的:它是一个用 Rust 写的命令行搜索工具,递归搜索当前目录下的正则表达式模式,同时自动遵循你仓库的.gitignore规则,装完就能直接用。
一装就能用:它默认替你做了什么
传统 grep 的哲学是"什么都不替你做,参数自己拼"。ripgrep 反过来:它假设你是在一个代码仓库里干活,于是默认就帮你做掉了四件脏活。
- 跳过
.gitignore里排除的文件,包括父目录里的.gitignore、仓库的$GIT_DIR/info/exclude,甚至你全局的 git 忽略配置; - 跳过隐藏文件和目录(就是那些点号开头的文件);
- 跳过二进制文件(它用"文件里有没有 NUL 字节"来判断);
- 不跟踪符号链接,避免死循环。
效果是:rg TODO src/出来的全是有效命中,不用再跟--include参数较劲。哪天真怀疑它把结果藏起来了,可以逐级加-u放开限制:-u恢复 gitignore 文件、-uu加回隐藏文件、-uuu连二进制文件一起搜。
# 演示默认行为:一条命令搜遍当前目录,自动跳过被忽略的文件 rg 'fn write\(' # 确认是过滤规则在起作用而不是漏搜:逐级放开限制 rg -uuu 'TODO'搜索整个目录就是默认模式,rg foo等价于rg foo ./,不用像 grep 那样显式加-r。
只搜某类文件,排除另一类
大型仓库里"全仓乱搜"常常不是想要的。ripgrep 内置了一套文件类型识别(Rust 对应-t rust、Python 对应-tpy),也可以随时排除:
# 只在 Rust 源码里找函数定义,JS 文件全部排除 rg -t rust -T js 'console\.'类型不满意可以自定义。配置文件里写两行,web这种"自造类型"就成立了:
# 演示自定义文件类型:把 html/css/js 归为一组,之后 rg -t web 就能用 --type-add web:*.{html,css,js}* --type-add docs:*.{md,rst}不想只看到匹配行?-l只列文件名,-c只数每个文件匹配了几行,--count-matches数的是总匹配次数——做"哪些文件受影响"式的排查时很顺手。
用 --replace 预览改写的效果
ripgrep 不能直接改文件(这是它有意的设计边界),但它的--replace参数可以把匹配到的片段替换成别的文本,输出里直接看效果,相当于一次"只读的重构演练":
# 演示替换预览:把命中 old_api 的位置在输出里显示成 new_api rg old_api --replace new_api配合--only-matching还能把整行裁成只剩匹配(含替换)的部分,做批量提取时有奇效。另外--smart-case值得一提:平时忽略大小写搜索,但一旦你的模式里出现大写字母,它就自动变回严格匹配——找FooBar这种驼峰命名时不用来回切换开关。
想要更"强"的正则?PCRE2 随时切换
ripgrep 默认用自己的正则引擎,速度快且完整支持 Unicode,但不支持环视(lookahead/lookbehind)和反向引用这类写法。需要这些高级语法时,加一个-P就切到 PCRE2 引擎(一种更全面的正则实现,语法和 Perl 一脉相承),也可以用--engine auto让它自己判断该不该切:
# 演示 PCRE2 语法:前面是数字才能命中 rg -P '\d{2,}x'代价是速度:PCRE2 引擎比默认引擎慢,crates/pcre2/ 这个模块的源码也说明了它只是一个可选项。所以官方建议:默认引擎够用就用默认,-P留给真正需要环视的场景。
一次配置,处处生效
常用选项不想每次敲?ripgrep 支持配置文件:设置环境变量RIPGREP_CONFIG_PATH指向一个文件(官方文档里的例子是~/.ripgreprc),之后每次运行都会自动带上里面的参数。文件格式很简单——每行一个参数,#开头是注释:
# ~/.ripgreprc 的完整示例:每次搜索自动带上的参数 --smart-case --max-columns=150 --max-columns-preview --colors=line:style:bold命令行参数优先级更高,临时想覆盖配置(比如--max-columns 0)直接敲命令即可。项目层面,你也可以在仓库根目录放一个.rgignore文件写自己的忽略规则,优先级高于.gitignore——适合"git 不想追踪但搜索又需要"的那批文件,比如本地日志。
速度到底来自哪里(以及什么时候它会变慢)
ripgrep 的快不是玄学,README 里的基准测试给过很具体的数字:在 Linux 内核源码树上(编译过的完整代码树)用同样的词边界模式搜索,rg 耗时 0.082 秒,而git grep(Unicode 模式)要 2.67 秒,ack要 2.9 秒。它的手段包括:并行递归遍历目录(每个 CPU 核分文件搜)、给大文件用内存映射(mmap,让操作系统按页加载文件,不用整块读进内存)、以及把 UTF-8 解码直接编进匹配引擎里——所以开着 Unicode 搜索也不掉速。
但 README 自己也很诚实地列了"性能悬崖":如果模式里没有任何可提前定位的固定片段(比如[A-Za-z]{30}这种),引擎没法做"字面量快速跳过",大文件上 rg 也要跑十几秒;命中量巨大时(比如搜the出了 8300 万行),瓶颈变成输出速度,各家工具的差距反而缩小。也就是说:ripgrep 快的前提是你给它一个正常的搜索任务,拿它当通用正则暴力扫描器时别期待魔法。
从源码看它是怎么拼起来的
仓库的 crates/ 目录把功能拆成了职责单一的模块:ignore管文件遍历与过滤,searcher管逐行读取(含内存映射策略),regex管默认正则引擎,printer管彩色输出和 JSON 格式,cli是把这些串起来的入口。这种拆分的好处是——你只关心"它怎么判断一个文件该不该搜"时,看 crates/ignore/ 一个目录就够了,不用通读整个项目。
装一个rg,你会发现终端里"找代码"这件事,从一堆参数变成了敲两个词。
【免费下载链接】ripgrepripgrep recursively searches directories for a regex pattern while respecting your gitignore项目地址: https://gitcode.com/GitHub_Trending/ri/ripgrep
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考