一个冒号什么也不做,尽管使用它
我写过的shell脚本数不胜数,但我仍然会偶尔遇到一些技术,老实说,这让我感到震惊,远比我愿意承认的要多。最近让我惊掉下巴的事情?那个shell冒号。2026年7月23日03:53 UTC发布,2026年7月26日05:33 UTC修改,作者Filip Roséen,标签 #shell #posix #unix。在一个遥远的地方……那里有一杯太冷的咖啡和一杯刚泡好的过热咖啡。四个不同的终端,其中三个一个小时前就该关闭,而我真的(真的)不想写一个shell脚本。谁能想到一个单独的冒号会成为拯救白天和黑夜的那个人呢?注意:想马上让你震惊吗?看看更多冒号的先锋。检查必需的参数这是一段熟悉的舞步,到现在几乎已经成为肌肉记忆。你有一个脚本,它接受几个参数,其中一些是必需的;好吧,if语句就像之前无数次那样:if [ -z "$1" ]; then echo "缺少参数,正在中止。" 1>&2 exit 1 fi echo "你好 $1!"不过……如果我告诉你,上面的四行可以用一行替换呢?:" ${1:?缺少参数,正在中止。} " echo "你好 $1!" $ bash example.sh example.sh: line 1: 1: 缺少参数,正在中止。 $ bash example.sh refp 你好 refp!再看看,如果我们引用一个有适当名称的变量会发生什么——与之前的行为相同,但更容易识别;诊断信息包括我们的变量名!:" ${GREET_NAME:?缺少参数,正在中止。} " echo "你好 $GREET_NAME!" $ bash greet.sh greet.sh: line 1: GREET_NAME: 缺少参数,正在中止。参数扩展和:?的故事在上面的代码段中有两件事情发生,你正确地识别出其中一部分使用了参数扩展:语法${name:?diagnostic}检查$names是否未设置或为空——如果是,它就将诊断信息打印到标准错误,并且shell以非零状态退出,否则;如果变量已设置,它等同于$name。那么……另一个冒号呢?所以这是一个冒号,但另一个,在行首独自坐着的那个呢?:是null-command——一个内置的什么也不做,只是评估它的参数并丢弃结果。:很古老——它可以追溯到1971年的汤普森shell,它既作为标签,又是Unix的第一个注释标记:两个眼睛在黑暗中注视着你,充满爱。更多冒号的先锋也许我们已经确定了,冒号不仅仅是表面看起来的,但为了证明null-command的真正魔力——这里有一些让我感到震惊的用法。:" ${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如果some-command; then:# 需要命令否则echo "命令失败" fi 总结因此,如果你和我一样,喜欢少打字(得快点)——那么null-command和参数扩展是一对值得研究的组合,趁你的咖啡没凉。还有……这不是——魔法吗?set : : : : : : : : : : : : : : : : : : : : : while : 冒号比" ${1:?魔法} "更多;做回显"$*"并移动done注意:上面的示例可以安全地在本地运行,试试看!常见问题在阅读了网上的一些评论后,似乎我跳过了一些值得解释的事情。我会根据问题的出现不断更新这一部分。为什么我需要null-command?扩展难道不在没有冒号时也会发生吗?参数扩展会发生,但是如果没有null-command或类似用法,shell会将结果字符串视为要运行的命令。% ${HELLO:=123} zsh: 找不到命令:123如果我们在参数扩展前加上null-command,结果将被丢弃,但表达式仍然被评估(将HELLO设置为123)。% : ${HELLO:=123} % echo $HELLO 123为什么要使用null-command,而不使用VAR=${VAR:-默认值}?这在其核心上归结为个人偏好,但使用我们所钟爱的冒号,我们可以将潜在的拼写错误减少到一个(而不是两个)::" ${DATA_DIR:=/var/data} " # <- DATA_DIR提到一次(1)DATA_DIR=" ${DATA_DRI:-/var/data} " # <- 哎呀(2)
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡