【问题标题】:Why are both "true" and "false" tests true?为什么“真”和“假”测试都是真的?
【发布时间】:2015-07-25 14:38:18
【问题描述】:

“true”和“false”这两个词是 bash 的特殊词(内置)。 如果在if 测试中使用,它们的行为与直觉预期的一样:

$ if true; then echo "true"; else echo "false"; fi
true
$ if false; then echo "true"; else echo "false"; fi
false

但是,这两个测试:

$ [[ true ]] && echo "true" || echo "false"
true
$ [[ false ]] && echo "true" || echo "false"
true

两者都为真。为什么?

【问题讨论】:

    标签: linux bash shell command-line-interface


    【解决方案1】:

    当我们使用 test 或其等效的 [ 时,有时会得到奇怪的结果。让我们试着理解为什么会这样。

    我们可以手动进行简单的测试:

    $ test 0    && echo "0 is T|$?" || echo "0 is F|$?"
    0 is T|0
    $ test 1    && echo "1 is T|$?" || echo "1 is F|$?"
    1 is T|0
    

    或者

    $ [ 0 ] && echo "0 is T|$?" || echo "0 is F|$?"
    0 is T|0
    $ [ 1 ] && echo "1 is T|$?" || echo "1 is F|$?"
    0 is T|0
    

    并且对以上两个测试都被报告为真实感到震惊。 测试告诉我们 0 等于 1 吗?

    要回答这个问题,我们可以创建一个测试函数并运行出现在this page 中的所有测试。
    该页面还旨在通过“测试”来解释所有详细信息。借助测试功能,我们可以运行类似于下一个的脚本。它打印测试结果和函数'test'的退出值:

    #!/bin/bash --
    tval(){
        printf "test %s\t" "$1"; shift
        [ "$@" ] && printf "%15s is T|%s" "$*" "$?" || printf "%15s is F|%s" "$*" "$?"
        printf "\n" 
    }
    
    tval "zero" "0"
    tval "one"  "1"
    tval "minus 1"  "-1"
    tval "string"   "xyz"
    tval "false"    "false"
    tval "true"     "true"
    
    tval "empty"    ""
    tval "Null"     ""
    tval "null var" "$xyz"
    tval "\$false"  "$false"
    tval "\$true"   "$true"
    

    结果:

    test zero                     0 is T|0
    test one                      1 is T|0
    test minus 1                 -1 is T|0
    test string                 xyz is T|0
    test false                false is T|0
    test true                  true is T|0
    test empty                      is F|1
    test Null                       is F|1
    test null var                   is F|1
    test $false                     is F|1
    test $true                      is F|1
    

    从以上所有测试中,一元测试的规则变得清晰:

     test 命令的思路很简单。
        它始终有效是一种非常简单的方法。
    任何时候测试值有一些内容, 也就是说,它的长度不为零, 它的结果是 TRUE。

    嗯,任何“一元”测试都是如此。 即测试对不能用空格分割的值执行。 二进制 [ -n $var ] 或三进制 [ 1 -eq "$one" ] 的测试 如果条件(-n-eq)有效,则返回真值。
    令人惊讶的是,这个(更复杂的)二元或三元测试更容易理解。存在大量较长的测试,但我觉得这些超出了这个简短问题的范围。

    有时用 -n 条件询问 var 是否不为零长度被称为迂腐,因为在没有任何明确条件的情况下会发生完全相同的测试。

    但是,当显式使用条件 -n 时,读者通常会更清楚程序员的目标是什么。
    条件 -z 测试“零长度”。

    通过这个测试:

    xyz="str";  tval "-n var"       "-n" "$xyz"
    xyz="str";  tval "-z var"       "-z" "$xyz"
    one=1;      tval "1 -eq \$one"  "1" "-eq" "$one"
    one=2;      tval "1 -eq \$one"  "1" "-eq" "$one"
    

    我们得到:

    test -n var              -n str is T|0
    test -z var              -z str is F|1
    test 1 -eq $one         1 -eq 1 is T|0
    test 1 -eq $one         1 -eq 2 is F|1
    

    测试中是否缺少任何方面?谢谢。

    【讨论】:

    • 建议你阅读test命令的POSIX定义;它比你的描述更简单也更复杂:pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
    • 那里,它清楚地表明:string True if the string string is not the null string; otherwise, false,非常简单,用于一元(单字)值。其余的变得相当复杂(我知道)。我尽量避免其他复杂的问题,以便为未来的读者提供有用的答案。谢谢。
    【解决方案2】:

    这是因为在您的第一个示例中,true 是一个内置命令。

    然而,在第二个例子中,[[ true ]] 中的 true 不被解释为命令,而只是被视为类似字符串的标记,如果字符串不为空,则返回 true。

    第二个例子可以这样写来修复:

    $ true && echo "true" || echo "false"
    true
    $ false && echo "true" || echo "false"
    false
    

    【讨论】:

      【解决方案3】:

      [[ … ]] 在这种情况下等同于test,即test truetest false。查看 test(1) 的手册:

      -n STRINGSTRING的长度非零

      STRING 等同于-n STRING

      truefalse 都是非空字符串。

      【讨论】:

      • 应该说的是 [[...]] 被改编为“与一元值中的测试相同”。 test,或者相当于[ 在所有(AFAIK)shell 和操作系统中的工作方式完全相同。同样,对于 UNARY(一个单词)值。这非常重要,因为这是最常用的测试之一。
      • @bize:不,这不是真正应该说的。 [[ ]] 基于 [ ]
      猜你喜欢
      • 2018-07-01
      • 2014-09-07
      • 2019-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      相关资源
      最近更新 更多