我已经暂时使用Bash脚本了,我想知道这两种形式的否定与test
命令之间是否存在差异:
if [ ! condition ]; then
fi
if ! [ condition ]; then
fi
第一个告诉shell传递参数! condition
进行测试,让程序自己处理否定。另一方面,第二个传递condition
来测试并让shell本身否定错误代码。
在选择这两种形式时,我应该注意哪些陷阱? $condition
的哪些值可以使它们之间的结果不同?
(我似乎记得刚刚在讨论这篇文章的时候读过一篇文章,但我不记得如何找到它/正是所讨论的内容。)
答案 0 :(得分:7)
在chepner对该问题的深刻见解的基础上进行构建:
在[ ! condition ]
中,!
只是 参数到[
内置(有效的别名) test
内置);恰好[
/ test
将参数!
解释为否定。
在! [ condition ]
中,!
是一个 shell关键字,否定了所遵循的任何命令(恰好是在这种情况下[
。)
! [ condition ]
语法隐含地给你的一点是,否定适用于{em}作为整体评估的[ condition ]
,所以如果这是意图,你需要&# 39;担心运营商优先权。
以性能为导向,您选择哪种语法可能并没有太大的区别;快速测试表明:
如果condition
在两种情况下都是相同的,那么将!
作为参数传递给[
的速度可以忽略不计。
如果将!
用作关键字,并且您因此可以通过不担心优先级来简化条件,则可能会稍快一些(例如,{{ 1}}与! [ 0 -o 1 ]
;请注意,由于歧义,POSIX规范不建议使用[ ! \( 0 -o 1 \) ]
和-a
。
也就是说,如果我们正在谈论 Bash ,那么您应该考虑使用-o
代替[[
,因为[
是一个 shell关键字,它在一个特殊的上下文中解析所附的表达式:
[[
和&&
请参阅我的this answer。
答案 1 :(得分:2)
!
否定以下命令的退出代码:
$ ! test 1 = 1 || echo $? # negate command with true expression
1
正如在手册页中所述,test
(以及类似的[
内置)退出,状态由以下表达式确定:
$ test ! 1 = 1 || echo $? # return false expression
1
$ [ ! 1 = 1 ] || echo $?
1
对于给定的表达式:
test
命令。 test
命令(或[
)以其错误状态退出两者都会产生同样的效果。
所以我想说这些语法是等价的。外部!
允许否定复合测试的优势:
$ ! [ 1 = 1 -a 2 = 2 ] || echo $?
1
答案 2 :(得分:0)
如果test
/ [
遇到错误,则有所不同。考虑:
x=abc
if [ ! "$x" -gt 0 ]; then echo "first true"; fi
if ! [ "$x" -gt 0 ]; then echo "second true"; fi
输出为:
bash: [: abc: integer expression expected
second true
与[[ .. ]]
不同,test
/ [
的工作方式类似于常规实用程序,并通过返回2
来指示错误。这是一个虚假的值,并且!
放在方括号之外,shell会将其反转,就像测试中的常规负结果反转一样。
与[[ .. ]]
的行为不同,因为条件中的语法错误是shell的语法错误,并且shell本身退出并显示错误:
if [[ a b ]]; then echo true; else echo false; fi
仅打印
bash: conditional binary operator expected
bash: syntax error near `b'
echo
没有任何输出。
另一方面,算术测试在[[ .. ]]
中的工作方式有所不同,因此[[ "$x" -gt 0 ]]
永远不会出错。