当前位置:  开发笔记 > 编程语言 > 正文

检查环境变量是否在Unix shell脚本中设置的简洁方法是什么?

如何解决《检查环境变量是否在Unixshell脚本中设置的简洁方法是什么?》经验,为你挑选了9个好方法。

我有一些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

这是很多打字.是否有更优雅的习惯用于检查是否设置了一组环境变量?

编辑:我应该提到这些变量没有有意义的默认值 - 如果有任何未设置,脚本应该出错.



1> Jonathan Lef..:

参数扩展

显而易见的答案是使用参数扩展的一种特殊形式:

: ${STATE?"Need to set STATE"}
: ${DEST:?"Need to set DEST non-empty"}

或者,更好(请参阅下面的"双引号位置"部分):

: "${STATE?Need to set STATE}"
: "${DEST:?Need to set DEST non-empty}"

第一个变体(仅使用?)需要设置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手册说:

${parameter:?word}

如果为空或未设置则显示错误.如果参数为null或未设置,则单词的扩展(或者如果单词不存在则为该效果的消息)将写入标准错误,并且如果shell不是交互式,则退出.否则,参数的值将被替换.

结肠司令部

我应该补充一点,冒号命令只是对其参数进行评估然后成功.它是原始的shell注释符号(在#'到行尾之前).很长一段时间,Bourne shell脚本都有一个冒号作为第一个字符.C Shell将读取一个脚本并使用第一个字符来确定它是用于C Shell(一个#'散列)还是Bourne shell(一个:'冒号).然后内核加入了该行为并添加了对' #!/path/to/program'和Bourne shell得到#'评论的支持,并且冒号大会走到了路边.但是如果你遇到一个以冒号开头的脚本,现在你就知道为什么了.


双引号的位置

blong在评论中问道:

对此讨论有何看法?https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749

讨论的要点是:

...但是,当我shellcheck(版本0.4.1),我收到此消息:

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}"

为了说明原因,请研究以下内容.请注意,该:命令不会回显其参数(但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推荐应该修复的内容.我没有验证它不反对表达式用双引号括起来的形式,但是它是合理的假设它会没问题.


它在shell手册页或Bash手册中记录,通常位于标题"参数扩展"下.检查变量是否存在并设置为特定值(比如'abc')的标准方法就是:`if ["$ variable"="abc"]; 然后:好的; else:变量设置不正确; fi`.

2> David Schlos..:

试试这个:

[ -z "$STATE" ] && echo "Need to set STATE" && exit 1;


那是什么,是可读的.我全都是为了这一个.Bash脚本需要他们在该部门获得的所有帮助!
这相当冗长.分号是多余的.
但是,这并不区分未设置的变量和设置为空字符串的变量.
甚至更短的`[-z"$ STATE"] && {echo"需要设置STATE"; 1号出口; 看到[这篇博文](http://zipizap.wordpress.com/2012/05/23/bash-root-only-scripts/)

3> Rob Wells..:

您的问题取决于您正在使用的shell.

伯恩贝壳对你所追求的东西的影响很小.

但...

它确实有效,几乎无处不在.

试着远离csh.与Bourne外壳相比,它增加了它所添加的花里胡哨,但它现在真的吱吱作响.如果您不相信我,请尝试在csh中分离出STDERR!( - :

这里有两种可能性.上面的例子,即使用:

${MyVariable:=SomeDefault}

这是你第一次需要引用$ MyVariable.这需要环境.var MyVariable,如果当前未设置,则将SomeDefault的值赋给变量供以后使用.

您还有可能:

${MyVariable:-SomeDefault}

它只是将SomeDefault替换为您使用此构造的变量.它不会将值SomeDefault赋值给变量,并且在遇到此语句后,MyVariable的值仍为null.


CSH:(foo> foo.out)>&foo.err

4> 小智..:

当然最简单的方法是将-u开关添加到shebang(脚本顶部的行),假设您正在使用bash:

#!/bin/sh -u

如果任何未绑定的变量潜伏在内,这将导致脚本退出.


或者在脚本中使用set命令:`set -u`

5> Vincent Van ..:
${MyVariable:=SomeDefault}

如果MyVariable设置且不为null,则它将重置变量值(=没有任何反应).
否则,MyVariable将设置为SomeDefault.

以上将尝试执行${MyVariable},所以如果你只想设置变量do:

MyVariable=${MyVariable:=SomeDefault}


正确的版本:(1):$ {MyVariable:= SomeDefault}或(2):MyVariable = $ {MyVariable:-SomeDefault}

6> Adriano..:

在我看来,#!/ bin/sh的最简单和最兼容的检查是:

if [ "$MYVAR" = "" ]
then
   echo "Does not exist"
else
   echo "Exists"
fi

同样,这是针对/ bin/sh的,并且在旧的Solaris系统上也兼容.


我喜欢这个,因为阅读IMO非常简单.
被设置为空字符串与完全没有设置是截然不同的.在"未设置MYVAR"和"MYVAR ="之后,此测试将打印"不存在".

7> chepner..:

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



8> Mr.Ree..:

我一直用:

if [ "x$STATE" == "x" ]; then echo "Need to set State"; exit 1; fi

我恐怕没那么简洁了.

在CSH下你有$?STATE.


这将检查`STATE`是否为空或未设置,而不仅仅是未设置.

9> nicooga..:

对于像我这样的未来人,我想更进一步,并参数化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

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有