布尔测试 && 和 || 的问题在bash中

布尔测试 && 和 || 的问题在bash中

考虑以下:

root@debian-lap:/tmp echo "Step 1 " || echo "Failed to execute step 1" ; echo "Step 2"
Step 1
Step 2
root@debian-lap:/tmp

可以看到,第1条和第3条echo命令正常执行。

如果我的第一个命令失败,我想停止脚本并exit从中停止:

root@debian-lap:/home/fugitive echo "Step 1 " || echo "Failed to execute step 1" && exit 2 ; echo "Step 2"
Step 1 
exit
fugitive@debian-lap:~$ 

exit命令执行并退出 shell,即使第一个命令的退出代码是 0。我的问题是 - 为什么?

翻译过来,这不是说:

  • 回显“步骤1”
  • 如果命令失败,则 echo '无法执行步骤 1' 并退出脚本
  • 否则回显“第2步”

看看这个:

cmd foo1 || cmd foo2 && exit

不应该cmd foo2 and (&&) exit只在失败时执行吗cmd foo1

我缺少什么?

编辑

我正在添加第二个示例,这是我真正想做的事情(仍然是虚拟测试)

root@debian-lap:/tmp/bashtest a="$(ls)" || echo "Failed" ; echo $a
test_file  # < - This is OK
root@debian-lap:


root@debian-lap:/tmp/bashtest a="$(ls)" || echo "Unable to assign the variable" && exit 2; echo $a
exit
fugitive@debian-lap:~$   # <- this is confusing part

root@debian-lap:/tmp/bashtest a="$(ls /tmpppp/notexist)" || echo "Unable to assign the variable" ; echo $a
ls: cannot access /tmpppp/notexist: No such file or directory
Unable to assign the variable            # <- This is also OK
root@debian-lap:

答案1

因为最后执行的命令(echo)成功了。如果你想对命令进行分组,使用语句会更清楚if

if ! step 1 ; then
   echo >&2 "Failed to execute step 1"
   exit 2
fi

您还可以将错误消息分组并退出,{ ... }但这有点难以阅读。然而,这确实保留了退出状态的确切值。

step 1 || { echo >&2 "step 1 failed with code: $?"; exit 2; }

请注意,我将 更改&&为分号,因为我假设即使错误消息失败,您也想退出(并在 stderr 上输出这些错误以获得良好的实践)。

对于if保留退出状态的变体,您需要将代码添加到该else部分:

if step 1; then
  : OK, do nothing
else
  echo >&2 "step 1 failed with code: $?"
  exit 2
fi

(这也使得它与没有关键字的 Bourne shell 兼容!)。


作为或为什么命令组喜欢这样做,标准说

AND-OR 列表是由运算符 和 分隔的一个或多个管道的序列"&&""||"

运算符"&&""||"应具有相同的优先级,并应以左结合性进行评估。

这意味着 like 的somecmd || echo && exit行为就好像somecmdecho首先组合在一起,即 { somecmd || echo; } && exit和 not somecmd || { echo && exit; }

答案2

我认为问题在于二元/逻辑运算符的优先级。即“and”和“or”具有相同的优先级,因此以下行:
echo "Step 1 " || echo "Failed to execute step 1" && exit 2 ; echo "Step 2"本质上与: 相同
( echo "Step 1 " || echo "Failed to execute step 1" ) && exit 2 ; echo "Step 2"
你应该尝试echo "Step 1 " || ( echo "Failed to execute step 1" && exit 2 ) ; echo "Step 2"一下。

相关内容