bash - shell是什么 - unix shell中文




在Unix shell脚本中设置环境变量的简明方法是什么? (10)

参数扩展

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

: ${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 =“”(空字符串)是OK - 不完全符合您的要求,但是替代方法和旧方法。

第二个变体(使用:? )要求设置DEST并且非空。

如果您不提供消息,则shell会提供一条默认消息。

${var?}结构可以移植到版本7 UNIX和Bourne Shell(1978年左右)。 ${var:?}构造稍微更近一些:我认为它在1981年左右的System III UNIX中,但在此之前它可能在PWB UNIX中。 因此它在Korn Shell和POSIX shell中,特别是Bash。

它通常在shell的手册页中称为参数扩展部分。 例如, bash手册说:

${parameter:?word}

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

冒号命令

我应该补充一点,冒号命令只是简单地评估它的参数,然后成功。 它是最初的shell注释符号(在' # '之前到行尾)。 很长一段时间,Bourne shell脚本以冒号作为第一个字符。 C Shell将读取一个脚本并使用第一个字符来确定它是用于C Shell(' # '散列)还是Bourne shell(' : '冒号)。 然后内核加入了行为并增加了对' #!/path/to/program '的支持,并且Bourne shell得到了' # '注释,并且冒号惯例就在旁边。 但是,如果您遇到以冒号开头的脚本,现在您将知道原因。

双引号的位置

blong在comment问道:

对这个讨论有什么想法? 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建议应该修复的内容。 我没有证实它不反对表达式用双引号引起来的形式,但是它是合理的假设。

我有几个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

这是很多打字。 是否有更优雅的成语来检查是否设置了一组环境变量?

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


$? 语法非常整齐:

if [ $?BLAH == 1 ]; then 
    echo "Exists"; 
else 
    echo "Does not exist"; 
fi

上述解决方案中没有一个适用于我的目的,部分原因是我在开始漫长过程之前检查环境中是否需要设置变量的开放式列表。 我结束了这个:

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}

你的问题依赖于你正在使用的shell。

Bourne shell在你所追求的方面离开的很少。

但...

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

尽量远离csh。 与Bourne贝壳相比,它添加的花哨和哨子非常好,但它现在真的很吱吱作响。 如果你不相信我,试试在csh中分离出STDERR! ( - :

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

${MyVariable:=SomeDefault}

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

您也有可能:

${MyVariable:-SomeDefault}

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


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

尝试这个:

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

我一直使用:

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

恐怕不那么简洁。

在CSH下你有$?STATE。


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

#
# 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_not_null [-f] variable ...
#
function assert_not_null() {
  local fatal var num_null=0
  [[ "$1" = "-f" ]] && { shift; fatal=1; }
  for var in "[email protected]"; 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_not_null one two
echo test 1: return_code=$?
assert_not_null one two three
echo test 2: return_code=$?
assert_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


${MyVariable:=SomeDefault}

如果MyVariable设置为非空值,它将重置变量值(=没有任何反应)。
否则, MyVariable被设置为SomeDefault

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

MyVariable=${MyVariable:=SomeDefault}




shell