有些人坚持认为我们永远不应该使用 cat。
这种观点在最好的情况下是主观的看法,而在最糟糕的情况下则是有害的霸凌。
Shell 管道并不是静态的美物,它们是与 UNIX shell 之间的互动对话,通过这种对话,我们临时拼接各种工具,得到我们想要的定制结果。
以 cat 开头的 shell 管道能在探索阶段为我们提供最大的灵活性。下面是我常用的一个模式:
cat some-huge-file | head | ...
我可以通过反复试验填充后面的 ... 部分,而不必对整个输入文件运行命令。这有点类似于测试驱动开发的思路。
然后,当我觉得后续的命令已经完整时,我可以通过按键组合 Ctrl - P(上一个命令)、Ctrl - A(移动到行首)、Alt/Opt - F 两次(跳过 cat)以及 Alt/Opt - D 两次(删除)来从管道中移除 head。虽然写出来显得步骤很多,但我的手可以立刻完成这些操作,几乎不用思考。
具体的按键组合并不重要,或许在这里提到它们会让人感到困惑。但我想向大家展示我对 shell 管道的具体思考方式——它是一系列步骤:第一步是输入,最后一步是输出。在这种思路下,将 head 放在 cat 之后是顺理成章的。
有人可能会说,cat | head 是多余的,下面的命令看起来是等价的:
head some-huge-file | ...
之后,当管道构建完成时,可以修改为:
cat some-huge-file | ...
其余部分保持不变。这确实没什么问题,而且这样做与我描述的“第一步是与命令无关的输入”这一想法在概念上是等价的,并且代码更短。
那么,为什么我不这样做(直接用 head 而不是 cat)呢?因为对我来说,这只是一个局部最优解。
对于某些命令,这确实是最佳选择。但我并不总是通过 cat | head 构建命令。有时我会凭借之前的经验潜意识里知道事情会如何发展,虽然我不一定第一次就能构造出正确的 shell 命令,但我可能也能做到。通常,如果有错误,也只需一两处小调整就能解决。
在这种情况下,我的手并不会去管 head。所以对我来说,始终以 cat 开头的管道是一个全局最优解。我无需刻意思考 shell 管道是否会复杂,如果我选错了,也可以轻松在两者之间切换。
如果有人决定永远不使用 cat,这完全没问题,这只是个人偏好。但我不喜欢的是那些颁发“无用的 cat 奖”的人,强迫别人也停止使用它。我不知道这些人是被误导了,还是故意在找茬。