2

在这个问题中,已经展示了如何在 bash 中使用简洁的布尔变量。有没有办法用这些变量执行逻辑运算?例如如何得到这个:

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

3 回答 3

7

这确实有效:

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

也许有人可以解释为什么 -a 和 -o 运算符不起作用和 &&, ||, ! 做?

于 2012-06-18T08:06:57.760 回答
5

好的男孩和女孩,上课时间。

执行此行时发生了什么?

if true ; then echo 1 ; fi

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

它的作用是if执行一个或多个命令(或者更确切地说,管道),并且如果执行的最后一个命令的返回代码成功,它会在达到thenuntil之后执行命令fi。如果返回代码不成功,then则跳过该部分并在之后继续执行fi

if 不带开关,它的行为无论如何都不可修改。

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

true

它不会打印任何内容,但会将其返回码设置为0(又名“true”)。if将上面的语句改写成这样,可以更清楚地看出它是一个命令:

if /bin/true ; then echo 1 ; fi

这是完全等价的。

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

help [
man [

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

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

但同样,这总是正确的,所以它不是很有用。如果1并且2是变量会更有用

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正在做它的工作。在这里,我们传递test了四个参数。第二个参数是-lt一个开关,告诉test应该测试第一个参数和第三个参数,看看第一个参数是否小于第三个参数。第四个参数只标记命令的结束;当test作为[最后一个参数调用时,必须始终是].

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

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被执行时,它将是 testing is 20 less than 25?,这是真的,所以if将执行then语句。

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

var1=true
var2=false

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

if命令被评估时,它将变成

if ! true -a false ; then

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

如果您要使用调用它的版本替换上述内容,test它仍然无法按预期工作:

var1=true
var2=false

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

因为该if行将被评估为

if ! [ true -a false ; ] then

并且test不会将true其视为布尔关键字,也不会视为命令,而是视为字符串。由于非空字符串被视为“真”,test因此它总是会成功返回if,即使您说过

if ! [ false -a yourmom ] ; then

由于两者都是非空字符串-a,测试都为真,返回成功,它被反转!并传递给if,它不执行then语句。

如果你test用这个版本替换版本

if ! $var1 && $var2 ; then

然后它将被评估为

if ! true && false ; then

并且会这样处理:if执行true返回成功;由!;反转 因为第一个命令的返回码是失败的&&语句短路并且false永远不会被执行。因为最后执行的命令返回了失败,失败被传回if不执行then子句的那个。

我希望这一切都清楚了。

或许值得指出的是,您可以使用这样的结构:

! false && true && echo 1

哪个不使用if但仍然检查返回码,因为那是什么&&||用途。

test在不犯任何错误的情况下使用是一种黑色艺术。通常,bash[[使用[.

由于原始海报没有提供他正在努力完成的实际示例,因此很难就最佳解决方案提供任何具体建议。希望这对他有足够的帮助,他现在可以找出正确的做法。

于 2012-06-18T11:58:44.313 回答
1

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

这将起作用:

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

注意表达式周围的括号。

您需要test命令([在较新的语法中)才能使用这些键(-a-o)。

但是testnut run 命令本身。如果要检查命令的退出代码,则不能使用test.

于 2012-06-18T08:14:34.090 回答