Shell 中的冒号什么也不做。照样用它

一篇关于 POSIX shell 中空操作 `:` 命令的博客文章引发了争论:这种简短惯用法究竟是高明的利器,还是可读性的隐患。评论者指出,`:` 在参数校验、重定向和脚本技巧中确有实用价值,但许多人认为,把多行逻辑压缩成晦涩的一行会让 shell 脚本更难维护,尤其是在规模扩大时。讨论进一步延伸到对 shell 脚本本身的批评——它的坑、可移植性怪癖,以及在 Python、PowerShell 和 LLM 生成代码时代中的角色。

:(空操作)命令的用途

  • 许多人认为某些惯用法确实很有用,尤其是用于:
    • 校验必需参数/环境变量:${1:?missing argument}VAR="${VAR:?message}"
    • 提供默认值:: "${DOTFILES_PATH:=$HOME/.dotfiles}"
    • if/while 中充当占位符,当语法上需要一个命令时使用。
    • 在函数内充当“文档字符串”式的一行,或作为一个虚拟 alias 以便于发现。
  • 也有人认为,大多数例子都只是聪明但不实用,本质上只是把可读的代码压缩成了一行。

重定向、截断与可移植性细节

  • 有人指出, : >file 既会截断文件也会创建文件,而文章似乎低估了这一点。
  • 讨论澄清说,重定向本身不一定需要 :,但不同 shell 的行为不同(例如,zsh 对 < file 可能会输出文件内容,除非把它附着到 : 上)。
  • 子 shell 与非子 shell 的例子在 set -e / --posix 下表现不同,这也解释了在某些场景中为什么会用 ( : < file )
  • : 是内建命令,而 true 可能是外部工具;: 会安全地忽略参数,因此有时更受青睐。

可读性与花哨技巧

  • 强烈反对把多行、易懂的代码变成密集的一行。
  • 多位评论者认为,除了极小的脚本之外,代码应优先考虑清晰和显式错误处理,而不是追求简短。
  • 也有人把这些技巧看作有趣的谜题,适合个人使用或用于代码炫技,但不适合生产环境。

Shell 与其他语言(以及 LLM)

  • 多条评论认为,POSIX shell 语法从根本上就不适合较大的程序;为了可维护的脚本,更推荐 Python、Ruby 或 PowerShell。
  • 也有人为 shell 辩护,认为它尽管有很多怪癖,但在小型自动化和进程编排方面仍然独一无二,尤其在 ShellCheck 等工具辅助下更是如此。
  • 据说 LLM 很擅长生成复杂的 shell/Perl 脚本,但仍需要人工审查;质量问题和过度工程化是反复出现的抱怨。

替代 shell 与生态

  • 提到了 fish、nushell、oil、zsh,尤其是 PowerShell,认为它们更现代或更具表达力;争论点包括:
    • 启动时间和依赖体积。
    • 作为“系统 shell”还是作为脚本语言的适用性。
    • 冗长程度、复杂性以及跨平台可用性。