我对使用 Or & And 运算符感到困惑

我对使用 Or & And 运算符感到困惑
echo 1 && false && echo 2 || echo 3
1
3

echo 2 || echo 3
2

在上面的代码中,为什么在第一种情况下不打印 2 ?为什么在第二种情况下会打印 2 ?

答案1

更一般的问题shell 的控制和重定向运算符是什么?它的答案可能会回答你的问题,但我会给你一些经验法则供你参考。

  • 如果您有一个很长的和/或列表,那么您可能会将每个列表视为||“如果此列表中最近执行的部分失败的,运行下一部分”(其中“失败”表示返回非零退出状态)。

  • 使用相同类型的推理,您可能会说这&&意味着“如果此列表中最近执行的部分成功了,运行下一部分”(其中“成功”意味着返回零退出状态)。

上面描述的是通常所说的短路评估

以您的代码为例,假设每个代码echo都有机会执行(echo失败如果标准输出流已关闭):

echo 1 && false && echo 2 || echo 3

第一个echo 1成功,因此false运行。 false失败(按设计),所以echo 2 才不是跑步。echo 3,另一方面,由于列表 ( false) 的最近执行的部分失败而运行。

看着

echo 2 || echo 3

在这里,echo 2首先运行,但echo 3没有运行,因为列表中最近执行的部分没有失败。

答案2

&&我对||这个答案有一个简短的解释:https://unix.stackexchange.com/a/31881/4506m但这里有对您的特定示例的更详细解释。

首先,重要的是要知道 unix 命令成功或者失败无论它们可能产生或不产生什么输出。更准确地说,如果命令的退出状态为零,则该命令成功;如果退出状态非零,则命令失败,但从退出状态的角度思考是令人困惑的。

鉴于此,您可能想要考虑

  • cmd1 && cmd2 && ... && cmdN从左到右评估命令,直到失败为止,以及
  • cmd1 || cmd2 || ... && cmdN从左到右评估命令,直到成功为止。

那么,让我们从你的第一个例子

echo 1 && false && echo 2 || echo 3

&&由于没有括号的组合和运算会变得更加混乱||,这使得预期的分组不清楚。事实证明,&&||具有相同的优先级并且分组到左侧,但是像这样的混合序列常常令人困惑。这个表达式的准确含义是

( ( ( echo 1 && false ) && echo 2 ) || echo 3 )

好吧,这里发生了什么?

  • shell 开始计算( ... || echo 3 ),但要做到这一点,它必须首先计算左侧命令。

  • shell 开始计算( ... && echo 2 ),但要做到这一点,它必须首先计算左侧命令。

  • shell 开始计算( echo 1 && false ),但要做到这一点,它必须首先计算左侧命令。

  • shell 评估echo 1哪个总是成功,即以状态代码零退出。echo 1操作员并不关心打印某些内容的事实&&,但它解释了输出的第一行,1\n

  • 第一个操作数的左操作数( echo 1 && false )成功,因此 shell 继续计算右操作数false。这是总是失败的命令,因此&&整个表达式都会失败。

  • 的左操作数( ... && echo 2 )已经失败,因此 shell才不是执行echo 2,并且该表达式本身失败。

  • 的左操作数( ... || echo 3 )失败,因此 shell执行echo 3。此命令会生成第二行输出,但更重要的是对于||运算符而言,它始终会成功,因此and运算符echo的整个序列都会成功。&&||

  • 如果在运行命令后输入 ,echo $?您会看到值为零,表明上一个命令成功。

你的第二个例子可以通过上面概述的相同过程进行评估,但让我们详细介绍一下。

echo 2 || echo 3

这比您的第一个示例简单得多。 shell 执行以下步骤。

  • shell 开始计算echo 2 || echo 3,但要做到这一点,它必须首先计算左侧。

  • shell 评估echo 2.这将打印您的一个输出行,并成功。

  • shell 继续评估echo 2 || echo 3,但现在由于左手成功,状态规则||根本不评估右手(因此您不会得到另一行输出)。因为左边成功了,所以整个||表达式也成功了。

这很详细,但我希望它能有所帮助。

答案3

shell 按照严格的从左到右的顺序执行命令(对于 OR 和 AND 列表)。

在此命令中:

echo 1 && false && echo 2 || echo 3

第一个命令是echo 1.它被执行并且退出状态变为0(即使它在开始时已经是 0),因为 echo 的退出状态始终为0

当找到第一个命令时&&,退出状态为 0(从上面开始),这意味着执行成功,然后&&接受并执行下一个命令。

执行时false,退出状态变为 1(失败)。

找到 next 时&&,当前退出状态为 1,&&被拒绝并且下一个命令 ( echo 2) 不会被执行。

但该行仍然有更多代码,因此 shell 会转到下一项,即||.作为1此时的当前退出状态,将被接受并执行||下一个命令 ( )。echo 3

该命令echo 2 || echo 3非常容易分析。第一个命令(总是)被执行以获得退出代码。该退出代码是0,下一个||被拒绝并且echo 3不被执行。没有其他需要处理的,行尾。

相关内容