$ 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 语法高度依赖于上下文。也就是说,某个特定事物(如true
或false
)的含义在很大程度上取决于它出现的位置。在您的示例中,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的答案]