bash 如何测试“假”?

Dar*_*ber 4 linux bash conditional-statements

$ 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
Run Code Online (Sandbox Code Playgroud)

这是废话 IMO,我在这里错过了什么?

- 更新

所以下面是它的过程:

$ COND=false
$ if ! $COND; then echo 'do it'; fi
do it
$ if $COND; then echo 'do it'; fi
Run Code Online (Sandbox Code Playgroud)

但我想$COND在一个更大的测试表达式(或[[ {expr} && {expr} ]])中与其他条件表达式结合使用。因此,当$COND为 false 时,它​​不会[[ {expr} ]]以直观的方式在内部工作。[[ {expr} ]]当我需要的更像是以下内容时,这似乎有点误导:

$ COND=false
$ if ! $COND && test -d ${HOME}/bin ; then echo 'do it'; fi
do it
Run Code Online (Sandbox Code Playgroud)

Gor*_*son 5

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

  • false 作为命令:

    false; echo $?    # prints "1"
    if false; then echo "yep"; else echo "nope"; fi    # prints "nope"
    
    Run Code Online (Sandbox Code Playgroud)

    有一个名为“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)
    
    Run Code Online (Sandbox Code Playgroud)

    在所有这些情况下,命令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
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # prints "equal"
    
    Run Code Online (Sandbox Code Playgroud)

    这个有点奇怪,取决于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"
    
    Run Code Online (Sandbox Code Playgroud)

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