$ ls ~/bin | wc -l
137这是我上周敲的。137 个脚本,最早的一个是 2014 年写的,叫 ff,两行,作用是 find 加 grep。
我花了一个下午把这 137 个逐个打开看了一遍。这篇就是那个下午的产物。
盘点结果
我按「最近一年有没有用过」分了个类,结果挺让我难堪的:
- 经常用(每周至少一次):11 个
- 偶尔用(一年几次):19 个
- 一年没碰过:63 个
- 打开之后完全想不起来是干什么的:28 个
- 直接跑会报错的(依赖的服务或路径早没了):16 个
也就是说,我写的脚本里有超过一半是纯粹的垃圾,而且这些垃圾还在我的 PATH 里,随时可能被我手滑执行。
三个具体的翻车现场
一个叫 clean 的脚本
2016 年写的,作用是清理某个项目的构建产物。核心是 rm -rf $BUILD_DIR/*。
问题在于 BUILD_DIR 是从环境变量读的,没做检查。2019 年我换了 shell 配置,那个变量没了。我在家目录下敲了 clean,它执行的实际上是 rm -rf /*。
幸好非 root,删掉的东西有限,但我的 Downloads 和一个没提交的分支没了。从那天起我所有脚本第一行都是 set -euo pipefail,所有路径变量都做非空检查。
三个功能重叠的日志脚本
我有 tailerr、logs、lg 三个脚本,都是看日志的,写于不同年份。区别是过滤规则和颜色,其中两个还有 bug。
我为什么会写三个?因为每次要用的时候我都忘了自己写过,就又写了一个。脚本没有被发现的机制,就等于不存在。
一个跑了 40 分钟的脚本
一个数据核对脚本,我写的时候数据量是 20 万行,跑 30 秒。两年后数据是 900 万行,跑 40 分钟,而且中间没有任何进度输出。我有好几次以为它卡死了,Ctrl+C 掉重跑。
后来我加了一行进度打印,一共三行代码,我却拖了两年。
我做的整理
那个下午我干了这些事:
- 删掉 44 个(报错的 + 完全想不起来的)。删之前打了个 tar 包扔到备份盘,一个月后没人想它,就真删了。
- 剩下的每个脚本头部加三行注释:写于什么时候、解决什么问题、什么时候可以删掉。第三行是新加的,我觉得最有用。
- 写了一个
bin-help,扫描 ~/bin 下所有脚本的第二行注释,列成表。这样我至少知道自己有什么。 - 把三个日志脚本合并成一个,带子命令。
更根本的反思
整理完我在想一个问题:我这些年到底写了多少脚本,节省了多少时间?
粗略算:真正常用的 11 个,假设每个每周节省 5 分钟,一年是 47 小时。听起来不错。
但那 63 个没用过的呢?每个我至少花了半小时写和调,加起来 31 小时。再加上那次误删找回文件花的一天,以及三个重复脚本浪费的时间。
净收益仍然是正的,但比我想象的小得多。
我改变的三个习惯
第一,写脚本前先搜一遍。我给自己定了规矩:动手前必须 bin-help | grep 一次关键词。这个动作救了我好几次。
第二,区分「一次性」和「常驻」。一次性的东西我现在直接写在临时目录,或者干脆写在聊天记录里,不往 PATH 里放。只有连续用过三次的,才值得变成正式脚本。这个「三次法则」把我的脚本产出量砍了七成。
第三,超过 50 行就换语言。Shell 在 50 行以内是利器,超过之后错误处理、数据结构、测试全都变成折磨。我现在有个硬规定,shell 脚本超过 50 行就用 Python 重写,不讨价还价。
最后说个有点自嘲的观察:我发现自己写脚本最勤快的时期,恰好是工作最没成就感的时期。做真正重要的事情很难,而写一个小工具立刻就有反馈。这种「效率错觉」我陷进去过不止一次。现在我会警惕——如果我一周写了三个脚本,我该问问自己,我是不是在逃避什么更难的事。