Bash 差异或首选否定语句

sch*_*ity 5 bash shell-script test

bash 或语句否定的首选用法是否有区别?

if ! [[ -z "${var}" ]]; then
  do_something
fi
Run Code Online (Sandbox Code Playgroud)

相对

if [[ ! -z "${var}" ]]; then
  do_something
fi
Run Code Online (Sandbox Code Playgroud)

jes*_*e_b 7

! [[ expression ]]
Run Code Online (Sandbox Code Playgroud)

如果整个测试返回 false,这将是 true

[[ ! expression ]]
Run Code Online (Sandbox Code Playgroud)

如果单个表达式返回 false,则为 true。


由于测试可以是复合表达式,因此可能会有很大不同。例如:

$ [[ ! 0 -eq 1 || 1 -eq 1 ]] && echo yes || echo no
yes
$ ! [[ 0 -eq 1 || 1 -eq 1 ]] && echo yes || echo no
no
Run Code Online (Sandbox Code Playgroud)

就我个人而言,我更喜欢在适用的测试结构内部使用否定,但根据您的意图,在外部完全没问题。


ImH*_*ere 5

A! cmd实际上是一个pipe,并且!否定了整个管道的退出代码。

从人bash:

管道 管道是由一个控制运算符分隔的一个或多个命令的序列 | 或|&。管道的格式是:

         [time [-p]] [ ! ] command [ [|||&] command2 ... ]
Run Code Online (Sandbox Code Playgroud)

...
如果保留字!在管道之前,该管道的退出状态是上述退出状态的逻辑否定。shell 在返回值之前等待管道中的所有命令终止。

从这个意义上说,一个:

! [[ 2 -eq 2 ]]
Run Code Online (Sandbox Code Playgroud)

!整个退出代码的否定 ( ) [[(一旦所有退出代码都已执行)。因此,它的退出代码为 0:

!  [[ 2 -eq 2 && 3 -eq 4 ]]
Run Code Online (Sandbox Code Playgroud)

然而

A[[ ! ]]复合命令(不是管道)。从人bash:

复合命令
...
[[ expression ]]
根据条件表达式表达式的计算结果返回 0 或 1 状态。
表达式由以下条件表达式中描述的主要元素组成。

因此,它的退出代码为 1:

[[ ! 2 -eq 2 && 3 -eq 4 ]]
Run Code Online (Sandbox Code Playgroud)

因为这实际上相当于:

[[ ( ! 2 -eq 2 ) && ( 3 -eq 4 ) ]]
Run Code Online (Sandbox Code Playgroud)

其中,通过短路评估, 的右侧&&永远不会被评估,实际上相当于这个更短的表达式:

[[ ! 2 -eq 2 ]]
Run Code Online (Sandbox Code Playgroud)

这将永远是错误的(1)。

简而言之:在里面[[,!影响表达的部分

首选

使用!inside[[更为常见(并且可移植到更多 shell(使用[)),但如果没有通过明智地使用 明确控制()来界定否定的范围(这可能成为[构造内部的问题),有时可能会令人困惑。

但是(在 bash、ksh 和 zsh 中)的结果! [[定义非常明确且更容易理解:执行整个[[并否定结果。

应该使用哪个是个人喜好(和理解)的问题。