关于bash:对布尔变量的操作

Operations on boolean variables

在这个问题中,已经展示了如何在bash中使用整洁的布尔变量。有没有用这些变量执行逻辑操作的方法?例如,如何获得:

1
2
3
4
5
6
var1=true
var2=false
# ...do something interesting...
if ! $var1 -a $var2; then     <--- doesn't work correctly
   echo"do sth"
fi

这是可行的:

1
2
3
if ! $var1 && $var2; then
   echo"do sth"
fi

也许有人可以解释为什么-a和-o操作符不工作,以及&;&;,,!怎么办?


好了,孩子们,上课时间。好的。

执行此行时发生了什么?好的。

1
if true ; then echo 1 ; fi

这里发生的是执行if命令。之后发生的一切都是if命令的一部分。好的。

if所做的是执行一个或多个命令(或更确切地说,管道),如果上次执行的命令返回代码成功,则在then之后执行命令,直到到达fi为止。如果返回代码不成功,则跳过then部分,并在fi之后继续执行。好的。

if不接受开关,其行为无论如何都不可修改。好的。

在上面的例子中,我告诉if执行的命令是truetrue不是语法或关键字,它只是另一个命令。尝试自己执行:好的。

1
true

它将不打印任何内容,但它将返回代码设置为0(也称为"真")。您可以更清楚地看到这是一个命令,方法是重写上面的if语句,如下所示:好的。

1
if /bin/true ; then echo 1 ; fi

这是完全等效的。好的。

总是从测试中返回true并不是很有用。通常将iftest命令结合使用。test有时与[符号相连或以其他方式称为[。在您的系统上,您可能有一个/bin/[程序,但是如果您使用bash[将是一个内置命令。test是一个比if更复杂的命令,您可以阅读有关它的全部内容。好的。

1
2
help [
man [

但是现在让我们假设,test根据您提供的选项执行一些测试,并返回成功的返回代码(0)或不成功的返回代码。这让我们可以说好的。

1
if [ 1 -lt 2 ] ; then echo one is less than two ; fi

但同样,这总是正确的,所以它不是很有用。如果12是变量,则更有用。好的。

1
2
3
4
5
6
7
read -p' Enter first number: ' first
read -p' Enter second number: ' second
echo first: $first
echo second: $second
if [ $first -lt $second ] ; then
     echo $first is less than $second
fi

现在你可以看到,test正在做它的工作。在这里,我们将传递四个论点。第二个参数是-lt,它是一个开关,告诉test,第一个参数和第三个参数应该测试,看第一个参数是否小于第三个参数。第四个论点只标志着命令的结束;当把test称为[时,最后的论点必须始终是]。好的。

在执行上述if语句之前,对变量进行评估。假设我为first输入了20,为second输入了25,在评估后脚本将如下所示:好的。

1
2
3
4
5
6
7
read -p' Enter first number: ' first
read -p' Enter second number: ' second
echo first: 20
echo second: 25
if [ 20 -lt 25 ] ; then
     echo 20 is less than 25
fi

现在您可以看到,当执行test时,它将测试is 20 less than 25?,这是正确的,因此if将执行then语句。好的。

回到手头的问题:这里发生了什么?好的。

1
2
3
4
5
6
var1=true
var2=false

if ! $var1 -a $var2 ; then
    echo $var1 and $var2 are both true
fi

当评估if命令时,它将变为好的。

1
if ! true -a false ; then

这是指示if执行true并将参数-a false传递给true命令。现在,true不接受任何开关或参数,但是如果您不需要提供它们,它也不会产生错误。这意味着它将执行、返回成功,而-a false部分将被忽略。!将成功逆转为失败,而then部分将不被执行。好的。

如果您要用名为test的版本替换上述版本,它仍然无法按预期工作:好的。

1
2
3
4
5
6
var1=true
var2=false

if ! [ $var1 -a $var2 ] ; then
    echo $var1 and $var2 are both true
fi

因为if线的评估结果为好的。

1
if ! [ true -a false ; ] then

test将把true看作不是布尔关键字,也不是命令,而是字符串。由于test将非空字符串视为"真",因此它总是会将成功返回到if,即使您说过好的。

1
if ! [ false -a yourmom ] ; then

由于这两个字符串都是非空字符串,因此-a测试都为true,返回的成功与!相反,并传递给if,后者不执行then语句。好的。

如果用此版本替换test版本好的。

1
if ! $var1 && $var2 ; then

然后将其评估为好的。

1
if ! true && false ; then

处理方法如下:if执行true返回成功;!反向执行;由于第一个命令的返回码失败,&&语句短路,false从未执行。由于执行的最后一个命令返回了一个失败,失败被传递回不执行then子句的if。好的。

我希望一切都清楚。好的。

也许值得指出的是,您可以使用如下结构:好的。

1
! false && true && echo 1

它不使用if,但仍然检查返回代码,因为这是&&||的用途。好的。

使用test而不犯任何错误,这是一种黑色艺术。一般来说,在使用bash时,应该使用较新的[[命令,因为它更强大,而且可以消除许多gotcha,出于兼容性的原因,这些gotcha必须保存在[中。好的。

因为最初的海报没有提供一个现实的例子来说明他试图完成什么,所以很难给出任何关于最佳解决方案的具体建议。希望这已经足够有帮助了,他现在可以找到正确的事情做。好的。好啊。


这里混合了两种不同的语法。

这将起作用:

1
2
3
if ! [ 1 -a 2 ]; then
   echo"do sth"
fi

注意表达式周围的括号。

您需要使用test命令(新语法中的[来使用这些键(-a-o等等)。

但是,test执行nut运行命令本身。如果要检查命令的退出代码,则不能使用test