检查环境变量是否在 Unix shell 脚本中设置的简洁方法是什么? [英] What's a concise way to check that environment variables are set in a Unix shell script?

查看:19
本文介绍了检查环境变量是否在 Unix shell 脚本中设置的简洁方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些 Unix shell 脚本,我需要在开始做事情之前检查某些环境变量是否已设置,所以我做了这样的事情:

if [ -z "$STATE" ];然后echo "需要设置状态"出口 1菲如果 [ -z "$DEST" ];然后echo "需要设置 DEST"出口 1菲

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

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

解决方案

参数扩展

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

: ${STATE?"Need to set STATE"}: ${DEST:?"需要设置DEST非空"}

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

: "${STATE?Need to set STATE}":"${DEST:?需要设置DEST非空}"

第一个变体(仅使用 ?)需要设置 STATE,但 STATE="(一个空字符串)是可以的——不完全是你想要的,而是替代的和旧的符号.

第二种变体(使用 :?)需要设置 DEST 且非空.

如果您不提供任何消息,shell 将提供一条默认消息.

${var?} 结构可移植回第 7 版 UNIX 和 Bourne Shell(1978 年左右).${var:?} 构造稍晚一些:我认为它大约在 1981 年出现在 System III UNIX 中,但在此之前它可能已经出现在 PWB UNIX 中.因此,它在 Korn Shell 和 POSIX shell 中,特别是在 Bash 中.

它通常记录在 shell 的手册页中名为 参数扩展.例如,bash 手册说:

<块引用>

${parameter:?word}

如果为空或未设置则显示错误.如果参数为 null 或未设置,则 word 的扩展(或如果 word 不存在则显示该效果的消息)将写入标准错误,并且如果 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)时,我收到此消息:

在 script.sh 第 13 行:: ${FOO:?"必须设置环境变量‘FOO’并且非空"}^-- SC2086:双引号以防止通配和分词.

在这种情况下我应该怎么做有什么建议吗?

简短的回答是按照 shellcheck 的建议去做":

: "${STATE?Need to set STATE}":"${DEST:?需要设置DEST非空}"

为了说明原因,请研究以下内容.请注意, : 命令不会回显其参数(但 shell 会评估参数).我们想看到参数,所以下面的代码使用 printf "%s " 代替 :.

$ mkdir 垃圾$ cd 垃圾$>美国广播公司$>定义$>吉$$ x=*"$ printf "%s
";${x:?你必须设置x}#粗心;不建议美国广播公司定义吉$ 未设置 x$ printf "%s
";${x:?你必须设置x}#粗心;不建议bash: x: 你必须设置 x$ printf "%s
";"${x:?您必须设置x}"#小心:应该使用bash: x: 你必须设置 x$ x=*"$ printf "%s
";"${x:?您必须设置x}"#小心:应该使用*$ printf "%s
";${x:?"You must set x"} # 不够仔细美国广播公司定义吉$ x=$ printf "%s
";${x:?"You must set x"} # 不够仔细bash: x: 你必须设置 x$ 未设置 x$ printf "%s
";${x:?"You must set x"} # 不够仔细bash: x: 你必须设置 x$

注意 $x 中的值如何扩展为第一个 * 和文件名列表,当整个表达式没有用双引号括起来时.这是 shellcheck 建议应该修复的.我没有验证它不反对用双引号括起来的表达式的形式,但它是一个合理的假设,它会没问题.

I've got a few Unix shell scripts where I need to check that certain environment variables are set before I start doing stuff, so I do this sort of thing:

if [ -z "$STATE" ]; then
    echo "Need to set STATE"
    exit 1
fi  

if [ -z "$DEST" ]; then
    echo "Need to set DEST"
    exit 1
fi

which is a lot of typing. Is there a more elegant idiom for checking that a set of environment variables is set?

EDIT: I should mention that these variables have no meaningful default value - the script should error out if any are unset.

解决方案

Parameter Expansion

The obvious answer is to use one of the special forms of parameter expansion:

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

Or, better (see section on 'Position of double quotes' below):

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

The first variant (using just ?) requires STATE to be set, but STATE="" (an empty string) is OK — not exactly what you want, but the alternative and older notation.

The second variant (using :?) requires DEST to be set and non-empty.

If you supply no message, the shell provides a default message.

The ${var?} construct is portable back to Version 7 UNIX and the Bourne Shell (1978 or thereabouts). The ${var:?} construct is slightly more recent: I think it was in System III UNIX circa 1981, but it may have been in PWB UNIX before that. It is therefore in the Korn Shell, and in the POSIX shells, including specifically Bash.

It is usually documented in the shell's man page in a section called Parameter Expansion. For example, the bash manual says:

${parameter:?word}

Display Error if Null or Unset. If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

The Colon Command

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.


Position of double quotes

blong asked in a comment:

Any thoughts on this discussion? https://github.com/koalaman/shellcheck/issues/380#issuecomment-145872749

The gist of the discussion is:

… However, when I shellcheck it (with version 0.4.1), I get this message:

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.

Any advice on what I should do in this case?

The short answer is "do as shellcheck suggests":

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

To illustrate why, study the following. Note that the : command doesn't echo its arguments (but the shell does evaluate the arguments). We want to see the arguments, so the code below uses printf "%s " in place of :.

$ mkdir junk
$ cd junk
$ > abc
$ > def
$ > ghi
$ 
$ x="*"
$ printf "%s
" ${x:?You must set x}    # Careless; not recommended
abc
def
ghi
$ unset x
$ printf "%s
" ${x:?You must set x}    # Careless; not recommended
bash: x: You must set x
$ printf "%s
" "${x:?You must set x}"  # Careful: should be used
bash: x: You must set x
$ x="*"
$ printf "%s
" "${x:?You must set x}"  # Careful: should be used
*
$ printf "%s
" ${x:?"You must set x"}  # Not quite careful enough
abc
def
ghi
$ x=
$ printf "%s
" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ unset x
$ printf "%s
" ${x:?"You must set x"}  # Not quite careful enough
bash: x: You must set x
$ 

Note how the value in $x is expanded to first * and then a list of file names when the overall expression is not in double quotes. This is what shellcheck is recommending should be fixed. I have not verified that it doesn't object to the form where the expression is enclosed in double quotes, but it is a reasonable assumption that it would be OK.

这篇关于检查环境变量是否在 Unix shell 脚本中设置的简洁方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆