两者之间更喜欢什么
if ! [ ... ]; then
和
if [ ! ... ]; then
实际上它们的结果相同,有首选语法吗?在前一种语法中,评估的 not 是 shell 内置的,而在后一种语法中, not 是内置的test
,这有什么区别吗?
答案1
可移植性的考虑。
关键字!
是 POSIX 但不是 Bourne,而/命令从一开始!
就支持。[
test
所以[ ! ... ]
比! [ ... ]
.
否则,只要您不使用已弃用的运算符-o
和-a
二元运算符,它们就应该是等效的(如果我们抛开某些旧test
/[
实现中的解析错误)。
实际上,在 Bourne shell 中,要做
if ! cmd1; then
cmd2
fi
你必须这样做:
if cmd1; then
:
else
cmd2
fi
(或使用cmd1 || cmd2
,尽管这最终可能会导致不同的退出状态)。
set -o errexit
//与set -e
陷阱交互ERR
if
在/语句的条件部分之外fi
,正如 @mosvy 所指出的,[ ! ... ]
和之间的另一个区别是,后者在返回 false 且选项打开! [ ... ]
时不会导致 shell 退出。! [ ... ]
errexit
!
应用于任何管道会取消 的效果,errexit
因为 shell 认为管道的退出状态被用作状况。这同样适用于failing-pipeline || cmd
或failing-pipeline && cmd
...
而 with [ ! ... ]
,!
只是传递给[
命令的常规参数,最终就 shell 而言errexit
,它只是[
返回成功或失败退出状态的命令。
$ sh -ec '[ ! a = a ]; echo here'; echo "$?"
1
$ sh -ec '! [ a = a ]; echo here'; echo "$?"
here
0
if
当这些命令作为//while
语句的条件部分运行时until
,这不适用,如其中所示,errexit
不适用。
这同样适用于ERR
类似 Korn 的贝壳的陷阱:
$ ksh -c 'trap "echo OUCH" ERR; ! [ a = a ]'
$ ksh -c 'trap "echo OUCH" ERR; [ ! a = a ]'
OUCH
在实践中,这可能不会产生影响,因为[
几乎总是用作条件,而 whereerrexit
不适用(无论是在if
/ while
/until
语句中还是后跟&&
/ ||
)。
答案2
[ … ]
等于test …
,所以! [ … ]
等于! test …
。这意味着,您否定命令的结果test
。在本例中,!
是一个 shell 命令。
来自info bash
,例如在“管道”部分:
如果保留字‘!’在管道之前,退出状态是上述退出状态的逻辑非。
另一方面,[ ! … ]
意味着test ! …
。这意味着,您否定测试中的表达式。参见:!
man test
! EXPRESSION
EXPRESSION is false
所以它可以有不同的含义。如果您有复杂的表达式,则否定可能仅适用于一部分。
这取决于你,你喜欢什么。