参数扩展
显而易见的答案是使用一种特殊的参数展开形式:
: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}
或者,更好的(参见下面“双引号的位置”一节):
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
第一个变体(使用just ?)要求设置STATE,但是STATE=""(空字符串)是可以的——不是你想要的,而是另一种更老的符号。
第二个变量(使用:?)要求DEST设置为非空。
如果您不提供消息,shell将提供一个默认消息。
$ {var吗?}构造可以移植回UNIX版本7和Bourne Shell(1978年左右)。$ {var: ?}构造的出现时间稍晚一些:我认为它出现在大约1981年的System III UNIX中,但在那之前可能出现在PWB UNIX中。因此,它在Korn Shell中,在POSIX Shell中,特别是Bash中。
它通常记录在shell的手册页中一个称为参数展开的部分中。例如,bash手册说:
${参数:?词}
如果为空或未设置显示错误。如果parameter为null或未设置,则word的展开(或者如果word不存在,则相应的消息)将被写入标准错误,并且shell(如果不是交互式的)将退出。否则,参数的值将被替换。
冒号命令
I should probably add that the colon command simply has its arguments evaluated and then succeeds. It is the original shell comment notation (before '#' to end of line). For a long time, Bourne shell scripts had a colon as the first character. The C Shell would read a script and use the first character to determine whether it was for the C Shell (a '#' hash) or the Bourne shell (a ':' colon). Then the kernel got in on the act and added support for '#!/path/to/program' and the Bourne shell got '#' comments, and the colon convention went by the wayside. But if you come across a script that starts with a colon, now you will know why.
双引号的位置
布隆在评论中问道:
对这个讨论有什么想法吗?https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749
讨论的要点是:
然而,当我shellcheck它(0.4.1版本),我得到这条消息:
script.sh第13行:
: $ {FOO: ?“必须设置环境变量'FOO',并且非空”}
^—SC2086:双引号防止词缀和分词。
在这种情况下我该怎么做,有什么建议吗?
简短的回答是“按照shellcheck建议的去做”:
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
为了说明原因,请研究以下内容。注意:命令不会回显它的参数(但是shell会计算参数)。我们希望看到参数,所以下面的代码使用printf "%s\n"来代替:。
$ mkdir junk
$ cd junk
$ > abc
$ > def
$ > ghi
$
$ x="*"
$ printf "%s\n" ${x:?You must set x} # Careless; not recommended
abc
def
ghi
$ unset x
$ printf "%s\n" ${x:?You must set x} # Careless; not recommended
bash: x: You must set x
$ printf "%s\n" "${x:?You must set x}" # Careful: should be used
bash: x: You must set x
$ x="*"
$ printf "%s\n" "${x:?You must set x}" # Careful: should be used
*
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
abc
def
ghi
$ x=
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
bash: x: You must set x
$ unset x
$ printf "%s\n" ${x:?"You must set x"} # Not quite careful enough
bash: x: You must set x
$
注意$x中的值是如何展开的,首先是*,然后是一个文件名列表,当整个表达式不是双引号时。这是shellcheck建议应该修复的。我还没有验证它不反对表达式被括在双引号中的形式,但这是一个合理的假设,它将是OK的。