Shell 冒号什么也不做,但尽管用它

Lobsters Hottest 工具

摘要

解释 shell 冒号(空命令)及其实际用途,如参数检查、设置默认值、文件操作等。

<p><a href="https://lobste.rs/s/eidh3u/shell_colon_does_nothing_use_it_anyway">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/25 12:03

# 一个 shell 冒号什么都不做。但请放心使用它。 来源:https://refp.se/articles/your-shell-and-the-magic-colon 我写的 shell 脚本多到数不清,但至今仍会频繁遇到一些让我大吃一惊的技巧,频率高到我自己都不好意思承认。最近一个让我彻底震惊的东西?就是 shell 冒号。 发布于 2026 年 7 月 23 日 03:53 UTC 作者 标签 - \#shell (https://refp.se/articles/tagged/shell) - \#posix (https://refp.se/articles/tagged/posix) - \#unix (https://refp.se/articles/tagged/unix) ## 在很久很久以前…… ……有一杯太凉的咖啡,旁边是一杯刚泡好、太烫的咖啡。四个终端窗口,其中三个本来一小时前就可以关掉,还有一个我真的(真的)不想写的 shell 脚本。谁能想到,一个冒号就能拯救这个`白天`黑夜? > **注**:想立刻被震撼到?请见 > 其他值得记住的冒号 (https://refp.se/articles/your-shell-and-the-magic-colon#other-colons-worth-remembering)。 ## 检查必需参数 这是熟悉的套路,到这会儿已经形成肌肉记忆了。你有一个脚本,它接受几个参数,其中一些是必需的;好吧,像往常一样用 if 语句: ``` if [ -z "$1" ]; then echo "missing argument, aborting!" 1>&2 exit 1 fi echo "Hello $1!" ``` 不过……如果我说上面四行代码可以用……一行替代呢? ``` : "${1:?missing argument, aborting!}" echo "Hello $1!" ``` ``` $ bash example.sh example.sh: line 3: 1: missing argument, aborting! $ bash example.sh refp Hello refp! ``` ### 参数扩展与 `:?` 的故事 前面那段代码里有两件事,你猜对了,其中一部分用到了参数扩展 (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02): - 语法 `${name:?diagnostic}` 检查 `$name` 是否未设置或为空——如果是,则将诊断信息打印到 *stderr*,并且 shell 以非零状态退出;否则, - 如果变量已设置,则等价于 `$name`。 ## 那个……另一个冒号 所以那是第一个冒号,那另一个呢?那个孤零零坐在行首的冒号? - `:` 是空命令 (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_16)——一个内建命令,什么都不做,只求值其参数并丢弃结果。 - `:` 很古老——它可以追溯到 1971 年的 Thompson shell (https://en.wikipedia.org/wiki/Thompson_shell#Design),当时它兼任标签 (https://www.in-ulm.de/~mascheck/bourne/PWB/goto.1.html) 和 Unix 的第一个注释标记。 - `:` 两只眼睛在黑暗中凝视着你,带着爱。 ## 其他值得记住的冒号 或许我们已经确定,`:` 的内涵远不止表面所见,但为了证明空命令 (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_16) 的真正魔力——这里有几个让我震撼的用法。 ``` : "${DATA_DIR:=/var/data}" # 设置默认值,: 消费结果 : "${RETRIES:=3}" # 而不是将其作为命令运行 ``` ``` : > error.log # 清空 error.log : > error.log > access.log # 同时清空 error.log 和 access.log ``` ``` ( : < dataset.json ) && echo YES # dataset.json 是否可读? ( : >> result.json ) && echo YES # result.json 是否可写? ``` ``` trap : INT # trap 需要一个命令 sleep 60 # sleep 可被中断 ``` ``` set -u # 未设置变量时报错 : "$DEPLOY_ENV" "$HOST" # 检查 DEPLOY_ENV 和 HOST ``` ## 结-冒-论 所以,如果你像我一样喜欢少打字(要快!)——那么空命令 (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_16) 和参数扩展 (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02) 是值得记住的好搭档。 ``` while : colons are more than punctuation; do echo "I love colons" sleep 1 done ```

相似文章

POSIX 不是 Shell

Hacker News Top

本文认为 POSIX 是一种规范,而非程序,并且像 bash 和 dash 这样的 Shell 实现即使在 echo 等基本命令上也表现不同。它呼吁在多个 Shell 之间进行测试,而不是依赖“POSIX 兼容性”这一概念来实现可移植性。

SQLite字符串中的NUL字符

Hacker News Top

SQLite允许字符串中包含NUL字符,但这可能导致字符串函数和CLI输出中出现意外行为;本文介绍了如何检测和删除嵌入的NUL字符。

两个路径分隔符的故事(2021)

Lobsters Hottest

解释了macOS如何处理两个路径分隔符(斜杠和冒号),这是由于它从经典Mac OS和NeXTSTEP双重继承而来,并且这导致文件在Finder中显示为斜杠,但在终端中显示为冒号。