Linux 测试命令之前/之后的否定是否有区别?

Linux 测试命令之前/之后的否定是否有区别?,linux,bash,shell,unix,terminal,Linux,Bash,Shell,Unix,Terminal,我已经编写Bash脚本有一段时间了,我想知道使用test命令这两种否定形式之间是否有什么区别: if [ ! condition ]; then fi if ! [ condition ]; then fi 第一个命令告诉shell传递参数!条件进行测试,让程序自行处理否定。另一方面,第二个通过条件进行测试,并让shell本身消除错误代码 在这两种形式之间进行选择时,我应该注意哪些陷阱?$condition的哪些值会使它们之间的结果不同 (我似乎记得不久前读过一篇讨论这个问题的文章,但我不记

我已经编写Bash脚本有一段时间了,我想知道使用
test
命令这两种否定形式之间是否有什么区别:

if [ ! condition ]; then
fi

if ! [ condition ]; then
fi
第一个命令告诉shell传递参数
!条件
进行测试,让程序自行处理否定。另一方面,第二个通过
条件
进行测试,并让shell本身消除错误代码

在这两种形式之间进行选择时,我应该注意哪些陷阱?
$condition
的哪些值会使它们之间的结果不同


(我似乎记得不久前读过一篇讨论这个问题的文章,但我不记得如何找到它/确切地说是讨论了什么。)

否定以下命令的退出代码:

$ ! test 1 = 1 || echo $?  # negate command with true expression
1
如手册页所述,
test
(和类似的
[
内置)退出,状态由以下表达式确定:

$ test ! 1 = 1 || echo $?  # return false expression
1
$ [ ! 1 = 1 ] || echo $?
1
对于给定表达式:

$ test ! 1 = 1 || echo $?  # return false expression
1
$ [ ! 1 = 1 ] || echo $?
1
  • 在一方面,您否定了以真实表达式状态退出的
    test
    命令
  • 另一方面,您对表达式求反,然后
    test
    命令(或
    [
    )以其false状态退出
两者的效果相同

所以我认为这些语法是等价的。外部
允许否定复合测试的优点是:

$ ! [ 1 = 1 -a 2 = 2 ] || echo $?
1
要基于作者对该问题的深刻评论:

  • [!condition]
    中,
    只是内建的
    [
    的一个参数(测试的有效别名)
内建的;
[
/
测试
将参数
解释为否定

  • ![condition]
    中,
    是一个shell关键字,它否定任何后跟的命令(在本例中,它恰好是
    [

  • ![condition]
    语法隐式地告诉您的一件事是,无论
    [condition]
    作为一个整体计算结果是什么,否定都适用于它,因此,如果这就是目的,您就不必担心运算符优先级

    性能方面,您选择的语法可能没有多大区别;快速测试建议:

    • 如果两种情况下的
      条件
      完全相同,则将
      作为参数传递给
      [
      的速度要快得多

    • 如果将
      用作关键字,因此您可以通过不考虑优先级来简化条件,它可能会稍微快一点(例如,
      ![0-o1]
      [!\(0-o1\)]
      ;请注意,POSIX规范不鼓励使用
      -a
      -o

    这就是说,如果我们谈论的是Bash,那么您应该考虑使用
    [[/code>而不是
    [[/code>,因为
    [[/code>是一个shell关键字,它在特殊上下文中解析封闭表达式,该上下文:

    • 提供更多功能
    • 允许您安全地将表达式与
      &&
      | |
    • 带来的惊喜更少
    • 也稍微快一点(尽管在实践中这几乎不重要)

    请参阅我的。

    如果
    测试
    /
    [
    遇到错误,则存在差异。请考虑:

    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
    
    [[…]]
    不同,
    测试
    /
    [
    的工作原理与常规实用程序类似,并通过返回
    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
    s的输出


    另一方面,算术测试在
    [[…]]
    so
    [[“$x”-gt 0]]中的工作方式不同
    永远不会给出错误。

    您可能会注意到,第一组中第三个示例的轻微修改也会报告
    1
    test!false | echo$?
    。这是因为测试正在检查字符串(
    true
    false
    )是否为空。与第一组中的第二个示例类似;用
    false
    替换
    true
    不会改变结果。你是对的。将其替换为我应该是的:表达式。也许你应该注意
    =
    bash
    上工作,但不是
    dash
    。使用POSIX语法更新。不是真正的pit总之,由于很难构建一个实际的场景来实现这一点,但请记住,在
    ![condition]
    中,
    是一个shell操作符,否定命令的退出状态,而在
    [!condition]
    中,
    只是
    [
    命令的一个字符串参数。在
    foo之后=“!bar”
    ,将
    [“$foo”]
    [$foo]
    进行比较。