为啥在 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语句未被评估为true
如何在 Python 2.7 中评估 BASH-Like 命令 (if/elif/else) 语句