我有一些Unix shell脚本,我需要在开始做之前检查某些环境变量是否已设置,所以我做了这样的事情:
if [ -z "$STATE" ]; then
echo "Need to set STATE"
exit 1
fi
if [ -z "$DEST" ]; then
echo "Need to set DEST"
exit 1
fi
Run Code Online (Sandbox Code Playgroud)
这是很多打字.是否有更优雅的习惯用于检查是否设置了一组环境变量?
编辑:我应该提到这些变量没有有意义的默认值 - 如果有任何未设置,脚本应该出错.
Jon*_*ler 571
显而易见的答案是使用参数扩展的一种特殊形式:
: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}
Run Code Online (Sandbox Code Playgroud)
或者,更好(请参阅下面的"双引号位置"部分):
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
Run Code Online (Sandbox Code Playgroud)
第一个变体(仅使用?)需要设置STATE,但是STATE =""(空字符串)是正确的 - 不完全是你想要的,而是替代和旧的表示法.
第二个变体(使用:?)需要设置DEST并且非空.
如果您不提供任何消息,则shell会提供默认消息.
该${var?}构造可移植回到版本7 UNIX和Bourne Shell(1978或其左右).这个${var:?}构造稍微更近了:我认为它大概是1981年的System III UNIX,但在此之前可能已经在PWB UNIX中了.因此它位于Korn Shell和POSIX shell中,特别包括Bash.
它通常记录在shell的手册页中的一个名为Parameter Expansion的部分中.例如,bash手册说:
Run Code Online (Sandbox Code Playgroud)${parameter:?word}如果为空或未设置则显示错误.如果参数为null或未设置,则单词的扩展(或者如果单词不存在则为该效果的消息)将写入标准错误,并且如果shell不是交互式,则退出.否则,参数的值将被替换.
我应该补充一点,冒号命令只是对其参数进行评估然后成功.它是原始的shell注释符号(在#'到行尾之前).很长一段时间,Bourne shell脚本都有一个冒号作为第一个字符.C Shell将读取一个脚本并使用第一个字符来确定它是用于C Shell(一个#'散列)还是Bourne shell(一个:'冒号).然后内核加入了该行为并添加了对' #!/path/to/program'和Bourne shell得到#'评论的支持,并且冒号大会走到了路边.但是如果你遇到一个以冒号开头的脚本,现在你就知道为什么了.
对此讨论有何看法?https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749
讨论的要点是:
...但是,当我
shellcheck(版本0.4.1),我收到此消息:Run Code Online (Sandbox Code Playgroud)In script.sh line 13: : ${FOO:?"The environment variable 'FOO' must be set and non-empty"} ^-- SC2086: Double quote to prevent globbing and word splitting.关于在这种情况下我应该做什么的任何建议?
简短的回答是"按照shellcheck建议做":
: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"
Run Code Online (Sandbox Code Playgroud)
为了说明原因,请研究以下内容.请注意,该:命令不会回显其参数(但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
$
Run Code Online (Sandbox Code Playgroud)
请注意当整个表达式不是双引号时,值$x是如何扩展到第一个*然后是文件名列表.这是shellcheck推荐应该修复的内容.我没有验证它不反对表达式用双引号括起来的形式,但是它是合理的假设它会没问题.
Dav*_*gle 131
试试这个:
[ -z "$STATE" ] && echo "Need to set STATE" && exit 1;
Run Code Online (Sandbox Code Playgroud)
Rob*_*lls 57
您的问题取决于您正在使用的shell.
伯恩贝壳对你所追求的东西的影响很小.
但...
它确实有效,几乎无处不在.
试着远离csh.与Bourne外壳相比,它增加了它所添加的花里胡哨,但它现在真的吱吱作响.如果您不相信我,请尝试在csh中分离出STDERR!( - :
这里有两种可能性.上面的例子,即使用:
${MyVariable:=SomeDefault}
Run Code Online (Sandbox Code Playgroud)
这是你第一次需要引用$ MyVariable.这需要环境.var MyVariable,如果当前未设置,则将SomeDefault的值赋给变量供以后使用.
您还有可能:
${MyVariable:-SomeDefault}
Run Code Online (Sandbox Code Playgroud)
它只是将SomeDefault替换为您使用此构造的变量.它不会将值SomeDefault赋值给变量,并且在遇到此语句后,MyVariable的值仍为null.
小智 48
当然最简单的方法是将-u开关添加到shebang(脚本顶部的行),假设您正在使用bash:
#!/bin/sh -u
如果任何未绑定的变量潜伏在内,这将导致脚本退出.
Vin*_*ghe 38
${MyVariable:=SomeDefault}
Run Code Online (Sandbox Code Playgroud)
如果MyVariable设置且不为null,则它将重置变量值(=没有任何反应).
否则,MyVariable将设置为SomeDefault.
以上将尝试执行${MyVariable},所以如果你只想设置变量do:
MyVariable=${MyVariable:=SomeDefault}
Run Code Online (Sandbox Code Playgroud)
Adr*_*ano 23
在我看来,#!/ bin/sh的最简单和最兼容的检查是:
if [ "$MYVAR" = "" ]
then
echo "Does not exist"
else
echo "Exists"
fi
Run Code Online (Sandbox Code Playgroud)
同样,这是针对/ bin/sh的,并且在旧的Solaris系统上也兼容.
che*_*ner 17
bash4.2介绍了-v运算符,该运算符测试名称是否设置为任何值,甚至是空字符串.
$ unset a
$ b=
$ c=
$ [[ -v a ]] && echo "a is set"
$ [[ -v b ]] && echo "b is set"
b is set
$ [[ -v c ]] && echo "c is set"
c is set
Run Code Online (Sandbox Code Playgroud)
Mr.*_*Ree 16
我一直用:
if [ "x$STATE" == "x" ]; then echo "Need to set State"; exit 1; fi
Run Code Online (Sandbox Code Playgroud)
我恐怕没那么简洁了.
在CSH下你有$?STATE.
对于像我这样的未来人,我想更进一步,并参数化var名称,因此我可以遍历一个可变大小的变量名称列表:
#!/bin/bash
declare -a vars=(NAME GITLAB_URL GITLAB_TOKEN)
for var_name in "${vars[@]}"
do
if [ -z "$(eval "echo \$$var_name")" ]; then
echo "Missing environment variable $var_name"
exit 1
fi
done
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
372477 次 |
| 最近记录: |