Bash "if [false];"返回true而不是false,为什么?

为什么下面的输出是True?

#!/bin/sh


if [ false ]; then
echo "True"
else
echo "False"
fi

这将始终输出True,即使条件似乎另有指示。如果我删除括号[],那么它就工作了,但我不明白为什么。

271833 次浏览

您正在运行参数为“false”的[(又名test)命令,而不是运行命令false。由于"false"是非空字符串,test命令总是成功。要实际运行该命令,删除[命令。

if false; then
echo "True"
else
echo "False"
fi

我发现我可以做一些基本的逻辑运行如下:

A=true
B=true
if ($A && $B); then
C=true
else
C=false
fi
echo $C

使用true/false删除一些括号混乱…

#! /bin/bash
#  true_or_false.bash


[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false


$sourced && echo "SOURCED"
$sourced || echo "CALLED"


# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"


$sourced && return || exit

Bash的快速布尔入门

if语句接受一个命令作为参数(就像&&||,等等)。该命令的整数结果码被解释为布尔值(0/null=true, 1/else=false)。

test语句以操作符和操作数作为参数返回一个与if格式相同的结果代码。test语句的别名是[,它经常与if一起使用来执行更复杂的比较。

__ABC0和false语句什么都不做,只返回一个结果代码(分别为0和1)。所以它们可以在Bash中用作布尔字面值。但是如果你把语句放在一个它们被解释为字符串的地方,你就会遇到问题。在你的情况下:

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

所以:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

这类似于做echo '$foo' vs. echo "$foo"这样的事情。

当使用test语句时,结果取决于所使用的操作符。

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
# evaluates to true/success (returns 0 or null)

简而言之,如果你只是想测试某些东西的通过/失败(即“true”/“false”),然后将一个命令传递给你的if&&等语句,不带括号。对于复杂的比较,使用括号和适当的操作符。

是的,我知道在Bash中没有原生布尔类型这样的东西,并且if[true在技术上是“命令”;而不是“陈述”;这只是一个非常基本的函数式解释

添加上下文希望能够帮助您对这个主题提供一些额外的清晰度。对于BaSH新手来说,真/假语句的意义相当奇怪。以下面的简单例子及其结果为例。

该语句将返回"true"

foo=" "; if [ "$foo" ]; then echo "true"; else echo "false"; fi

但这将返回“错误”:

foo=" "; if [ $foo ]; then echo "true"; else echo "false"; fi

你知道为什么吗?第一个例子有一个引用的&;"字符串。这导致BaSH按字面意思处理它。所以,从字面意义上讲,一个空格不是空的。而在非字面意义上(上面的第二个例子),一个空格被BaSH(作为$foo中的值)视为'nothing',因此它等同于null(这里解释为'false')。

这些语句都将返回一个文本字符串"false"

foo=; if [ $foo ]; then echo "true"; else echo "false"; fi
foo=; if [ "$foo" ]; then echo "true"; else echo "false"; fi
foo=""; if [ $foo ]; then echo "true"; else echo "false"; fi
foo=""; if [ "$foo" ]; then echo "true"; else echo "false"; fi

有趣的是,这种类型的条件总是返回true:

这些语句都会返回一个"true"的结果:

foo=""; if [ foo ]; then echo "true"; else echo "false"; fi

注意区别;在条件语句中,变量名前面的$符号被省略了。括号之间插入什么词并不重要。BaSH将始终将此语句视为true,即使您使用的单词以前从未与同一个shell中的变量关联。

if [ sooperduper ]; then echo "true"; else echo "false"; fi

同样地,将它定义为一个未声明的变量确保它总是返回false:

if [ $sooperduper ]; then echo "true"; else echo "false"; fi

对于BaSH,这与编写:

sooperduper="";if [ $sooperduper ]; then echo "true"; else echo "false"; fi

另一个提示....

括号vs无括号

更令人困惑的是,这些IF/THEN条件的变化都有效,但返回相反的结果。

返回false:

if [ $foo ]; then echo "true"; else echo "false"; fi
if [ ! foo ]; then echo "true"; else echo "false"; fi

但是,这些函数将返回true的结果:

if $foo; then echo "true"; else echo "false"; fi
if [ foo ]; then echo "true"; else echo "false"; fi
if [ ! $foo ]; then echo "true"; else echo "false"; fi

当然,这将返回一个语法错误(以及'false'的结果):

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

困惑了吗?在开始的时候,在头脑中保持头脑清醒是相当具有挑战性的,特别是如果你习惯了其他高级编程语言的话。

正如@tripleee所指出的,这充其量是切线。

不过,如果你来到这里寻找类似的东西(就像我一样),这是我的解决方案

必须处理用户可访问的配置文件,我使用这个函数:

function isTrue() {
if [[ "${@^^}" =~ ^(TRUE|OUI|Y|O$|ON$|[1-9]) ]]; then return 0;fi
return 1
}

Wich可以这样用

if isTrue "$whatever"; then..

您可以更改“真相列表”;在regexp中,这个示例中的一个是法语兼容的,并将诸如&;Yeah, yes, on,1, Oui,y,true之类的字符串视为&;True"。

注意,'^^'不区分大小写