为什么 bash 以不同的方式解析相同的条件?

Why does bash parse same condition in different ways?

今天我 运行 遇到了奇怪的 bash 行为,我做了这个简单的例子:

#!/bin/bash

if true or ! true; then
    echo a;
else
    echo b;
fi

if true -o ! true; then
    echo a;
else
    echo b;
fi

if true || ! true; then
    echo a;
else
    echo b;
fi

if true or 
   ! true; then
    echo a;
else
    echo b;
fi

if true -o 
   ! true; then
    echo a;
else
    echo b;
fi

if true || 
   ! true; then
    echo a;
else
    echo b;
fi

输出结果出乎我的意料:

a
a
a
b
b
a

我被提示情况4和5是这样处理的:

pi@raspberrypi:~ $ if true or; ! true; then echo a; else echo b; fi
b
pi@raspberrypi:~ $ if true -o; ! true; then echo a; else echo b; fi
b

这是工作代码,但对我来说它看起来像是一个语法错误,在第 6 种情况下就是这样:

pi@raspberrypi:~ $ if true ||; ! true; then echo a; else echo b; fi
bash: syntax error near unexpected token `;'

问题是,这种行为是错误还是有意为之?如果这是故意的,那么这种差异的意义是什么?

假设 overall syntax of if is:

if
     list-of-commands
then
     another-list-of-commands
fi

如果list-of-commands 退出且退出状态为,则执行another-list-of-commands。零退出状态也称为“成功”,而 non-zero 则称为“失败”。

总的来说,任何命令列表的退出状态都是最后执行的命令的退出状态。

"list-of-commands"可以包含多个list-of-commands“里面”和里面的多个命令。你可以把整个脚本放在那里。

if true or ! true; then

true is a command 以零退出状态退出。可执行文件 true 使用 3 个参数执行 - 字符串 or、字符串 ! 和字符串 true。命令 true 忽略参数并以零退出状态退出。

注意 or 只是 or 字符串 or 它没有特殊含义。

if true -o ! true; then

同上,只是第二个参数是字符串-o。再一次 -o 是字符 -o.

if true || ! true; then

||很特别。 || 当左侧的命令以 non-zero 退出状态退出时,执行右侧的命令。 ||的退出状态是last执行的命令的退出状态。

true 以零退出状态退出。 ||不执行右侧。最后一个命令是 true 并以零退出状态退出。列表 true || ! true 的退出状态为零。

  if true or 
  ! true; then

格式:

if 
   true or 
   ! true
then

这里有两个命令。

第一个 true 命令使用一个参数 or 执行。它的退出状态被忽略。

然后执行true命令,它以零退出状态退出。 ! "inverts" 退出状态,所以 ! true 的退出状态是一个。

命令列表的退出状态true or ; ! true是执行的最后一个命令的退出状态! true 是最后一个,它以 non-zero 退出。执行转到 else 分支。

if true -o 
 ! true; then

同上。

if true || 
 ! true; then

空行或仅包含空格且仅在 || 之后的注释将被忽略。这与 if true || ! true; then 的情况完全相同。

if 
   true || 
   # yay a comment here

   # ^^ and empty lines too!
   ! true
 

then
if true ||; ! true; then

语法为command || command; 结束命令列表。 ||后没有命令。因此,这是一个语法错误。