为啥在 bash if 语句中未设置的变量被评估为 0

Posted

技术标签:

【中文标题】为啥在 bash if 语句中未设置的变量被评估为 0【英文标题】:Why an unset variable gets evaluated as 0 in bash if statement为什么在 bash if 语句中未设置的变量被评估为 0 【发布时间】:2017-11-14 01:14:18 【问题描述】:

我试图理解为什么未设置的变量被评估为 0。 在我编写的某些脚本中,仅在需要时才设置变量,有时则不需要。 所以这种行为会导致输出不正确。 这是否意味着我必须预设所有变量或至少添加检查它们是否已设置?

#!/bin/bash
#myvalue=0  #comment to simulate an unset variable.

if [[ $myvalue -eq 0 ]] ; then
   echo "OK"
fi

结果正常:

bash -x test.sh
+ [[ '' -eq 0 ]]
+ echo OK
OK

【问题讨论】:

试试if [ $myvalue -eq 0 ];then 当然你可以用-eq[;事实上,你是否应该使用[[ ... -eq ... ]] 值得商榷,因为你可以改用可读性更强的(( ... == ... )) 添加检查是否已设置很简单:if [[ $myvalue--1 -eq 0 ]] ; then(将默认值设置为 -1...选择您喜欢的任何默认值) 这么多年过去了,我觉得这个问题最讽刺的是[[是为了避免[的陷阱而引入的,但是(至少对我来说)[很好理解和[[ 令人困惑且容易出错! [-eq 使用非整数操作数时会给出一个很好的错误消息,而[[ 只是默默地忽略错误。 【参考方案1】:

[[ ... ]] 中的 -eq 运算符,因为它仅适用于整数值,所以会触发对其操作数的算术评估。在算术表达式中,未设置的变量默认为 0。算术评估的更明显演示:

$ if [[ 3 -eq "1 + 2" ]]; then echo equal; fi
equal

请注意,在您的示例中,您甚至不需要先扩展参数;算术评估将为您完成:

$ if [[ myvalue -eq 0 ]]; then echo equal; fi
equal
$ myvalue=3
$ if [[ myvalue -eq 3 ]]; then echo equal; fi
equal

此外,这是特定于 bash [[ ... ]] 命令的。对于 POSIX [-eq 不会触发算术评估。

$ if [ "$myvalue" -eq 0 ]; then echo equal; fi
bash: [: : integer expression expected
$ if [ myvalue -eq 0 ]; then echo equal; fi
bash: [: myvalue: integer expression expected

【讨论】:

我猜这就是你写的答案“在算术表达式中,未设置的变量默认为 0”。我不知道。也在 man bash 中寻找此类信息,但没有找到。 在手册页的 ARITHMETIC EVALUATION 部分中,有一句话“在不使用参数扩展语法的情况下按名称引用时,为 null 或未设置的 shell 变量的计算结果为 0。”不过,据我所知,数字比较运算符触发算术评估这一事实实际上并没有记录在案。 (我认为$myvalue,而不仅仅是myvalue,在未设置时被视为0这一事实可能是$myvalue未根据内部通常规则扩展的无意的副作用[[ ... ]].) 它也让我觉得也许我应该总是使用 [ ] 而不是 [[ ]] 。这样至少我会看到可能使我预设一个重要值的错误,以反对获得不需要的结果。 [[ 在非算术测试中明显优于[;应该只使用(( ... )) 进行算术运算。 (我刚刚看过;[[ 被记录为对其运算符的操作数应用算术扩展;但是,这仅适用于期望整数的运算符。[[ -f "1+2" ]],例如,正确检查名为 1+2 的文件,而不是 3。)【参考方案2】:

如果您希望文字值作为比较值,请使用 = 而不是 -eq

if [[ $myvalue = 0 ]] ; then
    echo "OK"
fi

算术二元运算符 (-eq) 如果 arg1 等于 0,则返回 true,$myvalue 是,无论设置为 0 还是根本不设置...'' 为 null,这等于零。

【讨论】:

以上是关于为啥在 bash if 语句中未设置的变量被评估为 0的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 if 语句中使用双感叹号?

如何在bash的if块中评估布尔变量? [复制]

如果在调用堆栈中显示块,则内部变量,即使if语句未被评估为true

如何在 Python 2.7 中评估 BASH-Like 命令 (if/elif/else) 语句

为啥我不能使用正则表达式来评估 if...else 语句 [重复]

为啥这个 if 语句以非布尔值成功?