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

这需要大量的打字。是否有更优雅的习惯用法来检查是否设置了一组环境变量?

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


当前回答

${MyVariable:=SomeDefault}

如果MyVariable被设置并且不为空,它将重置变量值(=什么都不发生)。 否则,MyVariable被设置为SomeDefault。

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

MyVariable=${MyVariable:=SomeDefault}

其他回答

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

伯恩壳对你要找的东西没什么影响。

但是…

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

试着远离csh。与伯恩的外壳相比,它添加的铃铛和哨子是好的,但它现在真的吱吱作响。如果你不相信我,试着在csh中分离出STDERR !(-):

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

${MyVariable:=SomeDefault}

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

你也有可能:

${MyVariable:-SomeDefault}

它只是用SomeDefault替换你使用这个构造的变量。它不会将值SomeDefault赋给变量,在遇到此语句后,MyVariable的值仍然为空。

我们可以写一个很好的断言来一次检查一堆变量:

#
# assert if variables are set (to a non-empty string)
# if any variable is not set, exit 1 (when -f option is set) or return 1 otherwise
#
# Usage: assert_var_not_null [-f] variable ...
#
function assert_var_not_null() {
  local fatal var num_null=0
  [[ "$1" = "-f" ]] && { shift; fatal=1; }
  for var in "$@"; do
    [[ -z "${!var}" ]] &&
      printf '%s\n' "Variable '$var' not set" >&2 &&
      ((num_null++))
  done

  if ((num_null > 0)); then
    [[ "$fatal" ]] && exit 1
    return 1
  fi
  return 0
}

示例调用:

one=1 two=2
assert_var_not_null one two
echo test 1: return_code=$?
assert_var_not_null one two three
echo test 2: return_code=$?
assert_var_not_null -f one two three
echo test 3: return_code=$? # this code shouldn't execute

输出:

test 1: return_code=0
Variable 'three' not set
test 2: return_code=1
Variable 'three' not set

更多这样的断言在这里:https://github.com/codeforester/base/blob/master/lib/assertions.sh

而不是使用外部shell脚本,我倾向于在登录shell中加载函数。我使用类似这样的辅助函数来检查环境变量,而不是任何设置变量:

is_this_an_env_variable ()
    local var="$1"
    if env |grep -q "^$var"; then
       return 0
    else
       return 1
    fi
 }

试试这个:

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

上述解决方案都不符合我的目的,部分原因是我在开始一个漫长的过程之前检查了环境中需要设置的开放式变量列表。最后我得出了这个结论:

mapfile -t arr < variables.txt

EXITCODE=0

for i in "${arr[@]}"
do
   ISSET=$(env | grep ^${i}= | wc -l)
   if [ "${ISSET}" = "0" ];
   then
      EXITCODE=-1
      echo "ENV variable $i is required."
   fi
done

exit ${EXITCODE}