Notes · 2025.10.25

没有 rg 的时候

文件列表用 find。

2 min · tools

rg 很好用。这台机器上它经常不在 PATH。我喜欢它的速度和默认忽略 .gitignore。喜欢归喜欢,缺了它,工作还得做。缺了还当它在,损失更大:搜索失败会被理解成「仓库里没有这个符号」,后面就会新建一份平行实现。平行实现比缺一个搜索工具贵。我在个人站和检测仓库都见过:工具搜不到符号,就再写一个同名函数。同名函数能编译。编译绿了,行为却分叉。分叉到演示那天,才知道搜失败被当成了「代码里没有」。

文件列表用 find

文件列表这一层,我用 find . -maxdepth 1 -type f -print。只看当前目录的文件,不递归进 .git 和 node_modules。递归要另写,且要自己排除目录。find 丑,但 macOS 自带。

我在 home 里开过一次会话,让工具「找这个仓库的锁文件」。没有 rg,它用 find 从家目录挖下去,挖到好几个 pnpm-lock.yaml。然后它选了一个最眼熟的开始改。改完我才发现,那是另一个项目。从那以后,一次会话一个主仓库,搜索范围先钉死。

maxdepth 1 是保护。保护我不要在个人站仓库里把整个 vendor 扫一遍。Jekyll 的依赖目录很大,扫一遍又慢又吵。真要搜正文,我指定 _posts 或 _pages,不要从根上糊一层。

看不可见字符:cat -v

BSD cat 没有 -A。我想看行尾空格、制表符、奇怪的控制字符,用 cat -v,或者用 Python 打一遍 repr。个人站的 md 里混过一次不间断空格,渲染看起来没问题,grep 对不上标题。我当了文件损坏,重写了一段。后来用 cat -v 才看见。

YAML front matter 对不可见字符更敏感。冒号后面如果混了特殊空白,Jekyll 构建报的错不一定指向那一行。我现在改 _posts 之前,若构建信息很怪,先看文件头,不先改主题配置。主题配置动一次,回滚比改一篇 md 疼。

Windows 同学丢过来的脚本,行尾是 CRLF。在这台机器上有时能跑,有时 shell 把 \r 吃进参数。cat -v 会把 \r 显示出来。这个比再装一个 dos2unix 更适合偶发文件。

依赖任何二进制之前先探测

rg、timeout、fd、bat,都是我在别的环境用顺手的。这台笔记本的 PATH 很瘦。探测失败就换 POSIX 能用的。不要在任务中途 brew install 一串,把个人环境变成隐式依赖。

agent 对 rg 的执着很强。它会连续试 rg、ripgrep,再放弃。放弃之后有的会写一个 Python 扫描器,扫得比 find 还猛,忽略规则还不对。我宁可它一开始就 find,慢一点,范围我能看懂。

探测的另一面是:不要因为没有 rg 就认为不能搜。能搜。只是命令不同。把「环境不完整」写成阻塞,是偷懒。真阻塞是仓库不在、权限不够、代理没挂。rg 不在,不是阻塞。

搜索失败不等于仓库里没有

这是我反复踩的坑。工具搜 timeout,这台机器命令不存在,同时代码库里有超时逻辑。两件事叠在一条日志里,读的人会以为代码也没有超时。智在旅途演示崩过之后,我把超时当功能写进接口。如果当时有人只看本机有没有 timeout 命令,会得出「你们没做超时」的结论。结论是错的。

所以我要求:搜命令是否存在,和搜仓库里是否有某个符号,分开写。前者用 command -v。后者用 find 加 grep,或编辑器自带搜索。混用会制造假缺失。

个人站这批笔记的文件名是拼音。搜中文标题,和搜文件名,又是两套。rg 默认很好用,是因为它常把这两套一起做了。没有它的时候,我先问自己在搜哪一套。

不打算把 rg 写成硬依赖

我可以给这台机器装 rg。装了之后,约定还是要写「经常没有」。实验室机器、评委演示机、CI,都不保证有。个人习惯可以装;仓库文档不能写「请先安装 ripgrep」。

收到的限制:文件列表用 find;不可见字符用 cat -v 或 Python;二进制先探测。这条比再装一个工具更省事。省的不是安装时间,是避免把本机口味写进项目。

个人站的 _posts 文件名是拼音,标题是中文。没有 rg 的时候,我先决定搜文件名还是搜正文。搜错一套,会得出「这篇不存在」。不存在的结论一旦写进交接,下一轮就会新建一篇同主题的帖。同主题两篇,口径会打架。打架再删,git 历史里留下一场没必要的来回。所以缺 rg 不可怕,可怕的是缺了还用它当「有没有」的唯一证据。

探测写进习惯,不写进祈祷

脚本开头先 command -v rg。没有就走 find。不要在文档里写「请先安装 ripgrep」当作本机已经有。这台机器经常没有。没有不是事故,当成事故才会去全局乱装。乱装和课设的 Python、站点的 Ruby 打架,排查会从站点漂到家目录。家目录里改项目,搜索会吞掉整个家。