bash 如何测试“false”?

bash 如何测试“false”?
$ false
$ echo $?
1

$ if [[ false ]]; then echo 'do it'; fi
do it

$ test false && echo 'do it'
do it

$ COND=false
$ echo $COND
false
$ if [[ $COND -ne 0 ]]; then echo 'do it'; fi
$ if [[ $COND -ne true ]]; then echo 'do it'; fi

在我看来这简直是无稽之谈,我到底忽略了什么?

- 更新

事情的进展如下:

$ COND=false
$ if ! $COND; then echo 'do it'; fi
do it
$ if $COND; then echo 'do it'; fi

但我想$COND在一个更大的测试表达式(或)中与其他条件表达式结合使用[[ {expr} && {expr} ]]。因此,当为假时,它无法以直观的方式$COND在内部工作。当我需要的更像是:[[ {expr} ]][[ {expr} ]]

$ COND=false
$ if ! $COND && test -d ${HOME}/bin ; then echo 'do it'; fi
do it

答案1

Shell 语法高度依赖于上下文。也就是说,某个特定事物(如truefalse)的含义在很大程度上取决于它出现的位置。在您的示例中,false有三种完全不同的含义:命令、字符串值和包含整数值的(不存在的)变量名。让我来看看这些例子:

  • false作为命令:

    false; echo $?    # prints "1"
    if false; then echo "yep"; else echo "nope"; fi    # prints "nope"
    

    有一个名为“false”的命令(通常是 /usr/bin/false,或执行相同操作的 bash 内置命令),它实际上除了以失败状态退出外不执行任何操作。作为退出状态,零表示成功(有点类似于真值),非零表示失败(有点类似于假值)。这与更常见的零=假、非零=真约定相反,但对于退出状态来说,它更有意义。

  • false作为未解释的字符串值:

    if [[ false ]]; then echo "yep"; else echo "nope"; fi     # prints "yep"
    if [[ true ]]; then echo "yep"; else echo "nope"; fi      # prints "yep"
    if [[ wibble ]]; then echo "yep"; else echo "nope"; fi    # prints "yep"
    if [[ "this is a string" ]]; then echo "yep"; else echo "nope"; fi    # prints "yep"
    [[ false ]]; echo $?    # prints "0" (=success)
    [ false ]; echo $?      # prints "0" (=success)
    test false; echo $?     # prints "0" (=success)
    

    在所有这些情况下,命令test或其同义词[或 bash 条件表达式[[ ]]都没有得到表达式,只有一个字符串,因此它们执行一个非常简单的测试:它是一个非零长度的字符串吗?“true”、“false”、“wibble”等都是非零长度,因此命令/表达式类似于真值,因此成功。比较:

    [[ "" ]]; echo $?    # prints "1" (=failure), because the string is zero-length
    [[ ]]; echo $?       # prints "1" (=failure), because there isn't even a string
    [ ]; echo $?         # same
    

    请注意,test[是普通命令,而“false”(和“wibble”等)只是它的一个参数。[[ ]]是一些可以代替命令使用的 bash 语法。它们的参数/内容的解析方式与命令名称本身不同。

  • false作为可能包含整数的变量名:

    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # prints "equal"
    

    这个有点奇怪,取决于 bash 如何[[ ]]测试数字相等的细节。请注意,在[[ ]](和[ ]test表达式)中,-eq测试数字相等,并=测试字符串相等。因此,例如,[[ 01 -eq 1 ]](因为 1 和 01 在数值上相等)为真,但[[ 01 = 1 ]]为假(因为它们不是同一个字符串)。在 的情况下[[ false -eq true ]],“true”和“false”不是整数值,因此 bash 尝试将它们转换为整数,方法是将它们视为变量名(并希望变量包含整数值)。事实上,两者都没有定义为变量,因此它们都计算为空字符串,这可以解释为整数 0。观察:

    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # prints "equal"
    if [[ false -eq 0 ]]; then echo "equal"; else echo "nope"; fi        # prints "equal"
    false=5
    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # now prints "nope"
    

    请注意,定义false为变量不会影响其其他用途;当用作命令时,它仍将以状态 1 退出,而当用作字符串时,它仍然只是“false”(而不是“5”)。

答案2

您没有运行false命令,而是使用[[(类似于test内置[命令)来评估表达式“false”,并且不给它任何其他东西来评估它正在执行以下操作:

字符串
-n 字符串
如果字符串的长度非零,则为真。

请参阅条件表达式部分man bash以了解更多信息。

if 执行给定的命令,然后检查它的退出状态。

[引用礼貌来自SO的答案]

相关内容