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”还是作为脚本语言的适用性。
- 冗长程度、复杂性以及跨平台可用性。