字节笔记本
2026年6月25日
写了个自动索引脚本,被 macOS 两个老 bug 教做人
我一直有个坏习惯:把所有配置、密钥、服务器文档都往 ~/Documents/google-drive 这个目录里塞。几年下来,它攒了 32 个子目录,从腾讯云主机的运维记录、x-ui 代理面板的节点配置,到 Apple 开发者账号的 AuthKey、各路云服务的 JSON Key,全混在一块儿。
更糟的是,我之前手写过一份索引。写的时候挺认真,逐条核对用途,写完就再没碰过。前几天想找个工具,打开一看——上面只有 12 个目录,剩下 20 个全没收录。新增的 3x-ui、cloudflare-cli、tailscale、router 这些,一个都没在。
索引一旦滞后,就等于没有。你问「某个工具在哪」,它答不上来,你又得回到手动翻文件夹的老路。人力维护索引这件事,从一开始就是错的——人总会忘。
于是我想:干脆做个 AI 技能(skill),一条命令自动扫描整个目录、按类别重新生成索引。从此要新鲜就刷新,要分类就改一张映射表。理想很丰满:不就是个 find 统计文件数、du 算大小、再排个版的脚本嘛。
结果我严重低估了它。这个「5 分钟的小任务」,最后耗了大半天,时间几乎全花在两个跟我的代码毫无关系的 bug 上。
第一个坑:macOS 自带的 bash,停在 2007 年
脚本第一版我用了关联数组(declare -A),那是 bash 4+ 才有的特性,写起来干净利落。逻辑都对,单元测试也过,可一真跑起来,发现只扫到一个目录。
加 trace 一调试,罪魁祸首现形:macOS 系统自带的 /bin/bash 是 3.2 版本,2007 年的,压根不认识关联数组。declare -A 在它眼里是个静默失败的语句,后面所有依赖它的逻辑全成了空转。
这事乍看离谱,细想又在情理之中。十多年前 Apple 和开源社区因为 GPL 协议闹了点不愉快,从那以后自带的 bash 就一直停在 3.2,再没升过级。你 Mac 上的终端跑的,可能是比这台机器本身还老的软件。
改起来倒不难:把逻辑重写成 POSIX sh + awk,不碰任何 bash 独有特性,系统自带的 /bin/sh 就能跑。第一个坑,绕过去了。
第二个坑:这个才真的离谱
第一个坑好歹有迹可循——版本旧嘛,不支持新语法,查得到。第二个坑让我盯着屏幕愣了半天。
重写完,索引能跑出 32 个目录了,数字也对,但分类全乱套:明明八竿子打不着的目录,全被塞进同一个类别,表格里一列排下去全是错的。
我把 awk 的分类逻辑抽出来单独测,撞见一个诡异现象:
a = "空/待清理"
b = "开发/工具"
a == b → 居然返回 true两个完全不同的字符串,awk 说它们相等。我又换了几组中文变量反复测,逻辑没毛病,结果就是错。最后一路排查到 locale 上,揪出真凶:macOS 自带的那个 awk(one true awk,版本 20200816),在 UTF-8 环境下对中文字符串的相等比较有 bug,会误判。
换句话说,只要字符串里带中文,这个 awk 的 == 就形同虚设。而我的类别名——「代理/科学上网」「凭证/密钥」「项目知识库」——清一色中文。整个分类逻辑等于摆设,难怪全乱。
修复出奇简单:在 awk 调用前加一句 LC_ALL=C,强制它走字节级比较(反正我比较的是完整字符串、不做字符级切片),中文立马就能正确比对。优先用 Homebrew 的 gawk 更稳,没有就回退系统 awk 配 LC_ALL=C。
可要是不知道这个坑,真能排查到怀疑人生。你的代码一行没错,逻辑无懈可击,测试全过——错的只是这个 2019 年就被人报告过、至今仍躺在系统里的 awk。
一点感悟
工具的坑不可怕,可怕的是踩过了却没记下来。
事后我把整个排查过程、两个 bug 的复现步骤和修复办法,原原本本写进了这个 skill 的故障排查文档。下次再有人(包括未来的我自己)撞上同样的怪象,至少有据可查,不用从头怀疑人生。
说到底,做技术最值钱的不是写出能跑的代码——那个谁都会。值钱的是那些让你愣半天、最后发现「原来如此」的瞬间。那些瞬间,才是真正值得写下来、传出去的东西。