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)
! [[ 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)
就我个人而言,我更喜欢在适用的测试结构内部使用否定,但根据您的意图,在外部完全没问题。
A! cmd
实际上是一个pipe,并且!
否定了整个管道的退出代码。
从人bash:
管道 管道是由一个控制运算符分隔的一个或多个命令的序列 | 或|&。管道的格式是:
Run Code Online (Sandbox Code Playgroud)[time [-p]] [ ! ] command [ [|||&] command2 ... ]
...
如果保留字!在管道之前,该管道的退出状态是上述退出状态的逻辑否定。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 中)的结果! [[
定义非常明确且更容易理解:执行整个[[
并否定结果。
应该使用哪个是个人喜好(和理解)的问题。