测试使用“ set -o nounset”时是否在bash中设置了变量


94

以下代码以未绑定变量错误退出。在仍使用set -o名词设置选项的情况下如何解决此问题?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

Answers:


97
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

在这种情况下,VALUE如果WHATEVER未设置,则最终为空字符串。我们正在使用{parameter:-word}扩展,您可以man bash在“参数扩展”下查找。


14
只需替换[ -z $ {VALUE}]; 与if [!-z $ {WHATEVER:-}];
Angelom 2011年

18
:-检查变量是未设置还是为空。如果要检查无论是取消设置,使用-VALUE=${WHATEVER-}。另外,一种更易读的方法来检查变量是否为空:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0 2011年

1
另外,如果$WHATEVER仅包含空格,则无法使用-请参阅我的答案。
l0b0 2012年

9
是否有理由使用“ ! -z”而不是“ -n”?
乔纳森·哈特利

31

如果要获得期望的结果,则需要引用变量:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

测试:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

我尝试了这个,但我对此功能感到惊讶...一切都正确,除了根据"info bash""${WHATEVER-}"应该":""-"(破折号)之前加一个冒号"${WHATEVER:-}",例如:,"${WHATEVER+defined}""+"(加号)之前加一个冒号,例如:"${WHATEVER:+defined}"。对我来说,无论有无结肠,它都可以起作用。在某些版本的'nix中,如果不包含冒号,它可能无法工作,因此应该添加它。
凯文·费根

8
不,-+:+,和:-都支持。前者检测变量是否已设置,后者检测变量是否已设置或为。摘自man bash:“省略冒号只会对未设置的参数进行测试。”
l0b0 2014年

1
没关系=)。你是对的。我不知道我怎么想念它。
凯文·费根

文档开始换句话说,如果包含冒号,则运算符将测试两个参数是否存在以及其值不为null;如果省略了冒号,则运算符仅测试是否存在。
Acumenus 2014年

8

那一个班轮怎么样?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z 检查是否为空或未设置变量


2
否,-z仅检查下一个参数是否为空。-zis只是[命令的一个参数。变量扩展发生在[ -z无能为力之前。
支石墓

1
这似乎是正确的解决方案,因为如果未设置$ VAR,它不会产生错误。@dolmen您能提供一个何时无法使用的示例吗?
克里斯·斯特里钦斯基

@dolmen已经阅读了有关参数扩展的各种bash资源,并发现了其他过于复杂的答案,我认为这没什么错。因此,您的“澄清”虽然在技术上是正确的,但实际上在实践中似乎毫无意义,除非您需要区分未设置状态和未设置状态。我测试了无固定值,空值和非空值(bash 4),并且几乎每次都做了广告。
JL Peyret

8

假设:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

如果希望非交互式脚本打印错误并在变量为null或未设置的情况下退出,请执行以下操作:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

如果您不希望脚本退出:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

你甚至可以使用[],而不是[[]]以上,但后者是优选的猛砸。

注意上面的冒号。从文档

换句话说,如果包含冒号,则运算符会测试参数是否存在以及其值是否不为null;如果省略了冒号,则运算符仅测试是否存在。

目前显然没有需要-n-z

总之,我通常可能只使用[[ "${VAR:?}" ]]根据示例,这将打印错误并在变量为null或未设置的情况下退出。


4

您可以使用

if [[ ${WHATEVER:+$WHATEVER} ]]; then

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

可能更具可读性。


字符串比较应使用标准(POSIX)=运算符,而不是==为了提高可移植性,并且[[[尽可能使用它。
詹斯(Jens)2012年

2
@Jens该问题特定于bash,包括set -o nounset特定于bash的问题。如果将a #!/bin/bash放在脚本的顶部,则实际上最好使用bash的增强功能。
布鲁诺·布鲁诺斯基

0

虽然这不是正是用例要求上面,我发现,如果你想使用nounset(或-u)的默认行为是你想要的:退出非零一个描述性的消息。

我花了很长时间才意识到这一点,我认为值得将其发布为解决方案。

如果只想在退出时回显其他内容或进行一些清理,则可以使用陷阱。

:-否则,运算符可能就是您想要的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.