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

fug*_*ive 4 shell bash shell-script

考虑以下:

root@debian-lap:/tmp echo "Step 1 " || echo "Failed to execute step 1" ; echo "Step 2"
Step 1
Step 2
root@debian-lap:/tmp
Run Code Online (Sandbox Code Playgroud)

如您所见,第 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:~$ 
Run Code Online (Sandbox Code Playgroud)

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

在翻译中,这不是说:

  • 回声“第1步”
  • 如果命令失败,则 echo 'Failed to execute step 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:
Run Code Online (Sandbox Code Playgroud)

ilk*_*chu 8

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

if ! step 1 ; then
   echo >&2 "Failed to execute step 1"
   exit 2
fi
Run Code Online (Sandbox Code Playgroud)

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

step 1 || { echo >&2 "step 1 failed with code: $?"; exit 2; }
Run Code Online (Sandbox Code Playgroud)

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

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

if step 1; then
  : OK, do nothing
else
  echo >&2 "step 1 failed with code: $?"
  exit 2
fi
Run Code Online (Sandbox Code Playgroud)

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


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

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

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

这意味着,类似somecmd || echo && exit的行为,就好像somecmdecho被第一组合在一起,即 { somecmd || echo; } && exitsomecmd || { echo && exit; }

  • 另外,请注意`A &amp;&amp; B || C` **不** 与 `if A; 相同;那么B;否则 C; fi` 当我们考虑如果 A 成功但 B 失败会发生什么。我建议坚持使用 `if` 命令以避免混淆和歧义。 (2认同)