我尝试在shell脚本中使用以下语法声明一个布尔变量:

variable=$false

variable=$true

这对吗?另外,如果我想更新这个变量,我会使用相同的语法吗?最后,下面使用布尔变量作为表达式的语法正确吗?

if [ $variable ]

if [ !$variable ]

当前回答

关于语法,这是一个简单的方法,我使用(通过例子)来一致和理智地管理布尔逻辑:

# Tests
var=
var=''
var=""
var=0
var=1
var="abc"
var=abc

if [[ -n "${var}" ]] ; then
    echo 'true'
fi
if [[ -z "${var}" ]] ; then
    echo 'false'
fi

# Results
# var=        # false
# var=''      # false
# var=""      # false
# var=0       # true
# var=1       # true
# var="abc"   # true
# var=abc     # true

如果变量从未被声明,答案是:# false

因此,将变量设置为true(使用这种语法方法)的简单方法是,var=1;相反,var = "。

参考:

如果var字符串的长度非零,则-n = True。

如果var字符串的长度为零,则-z = True。

其他回答

Bill Parker被否决了,因为他的定义与正常的代码约定相反。通常,true被定义为0,false被定义为非0。1对false有效,9999和-1也一样。函数的返回值也是一样——0表示成功,任何非0表示失败。对不起,我还没有足够的街头信誉来投票或直接回复他。

Bash建议现在使用双括号而不是单括号作为一种习惯,Mike Holt给出的链接解释了它们工作方式的差异。7.3. 其他比较操作符

首先,-eq是一个数值运算符,所以有代码

#**** NOTE *** This gives error message *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

将发出错误语句,期望得到整数表达式。这适用于任意一个参数,因为两者都不是整数值。然而,如果我们在它周围加上双括号,它将不会发出错误声明,但它将产生一个错误的值(好吧,在50%的可能排列中)。它将计算为[[0 -eq true]] = success,但也计算为[[0 -eq false]] = success,这是错误的(嗯,....如果这个内置是一个数值呢?)

#**** NOTE *** This gives wrong output *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then

还有其他的条件排列也会给出错误的输出。基本上,将一个变量设置为数值并将其与一个真/假的内置变量进行比较,或者将一个变量设置为真/假的内置变量并将其与一个数值进行比较的任何事情(上面列出的错误条件除外)。此外,任何将一个变量设置为true/false的内置变量,并使用-eq进行比较。所以避免使用-eq进行布尔比较,避免使用数值进行布尔比较。下面是会产生无效结果的排列的总结:

# With variable set as an integer and evaluating to true/false
# *** This will issue error warning and not run: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then

# With variable set as an integer and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=0;
if [ "${The_world_is_flat}" -eq true ]; then
#
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" == true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then


# With variable set as an true/false builtin and evaluating to true/false
# *** These statements will not evaluate properly: *****
The_world_is_flat=true;
if [[ "${The_world_is_flat}" -eq true ]]; then
#
if [ "${The_world_is_flat}" = 0 ]; then
#
if [[ "${The_world_is_flat}" = 0 ]]; then
#
if [ "${The_world_is_flat}" == 0 ]; then
#
if [[ "${The_world_is_flat}" == 0 ]]; then

那么,现在来看看什么是有效的。在比较和计算时使用真/假内置参数(Mike Hunt指出,不要用引号括起来)。然后使用一个或一个或两个等号(=或==)和一个或两个括号([]或[[]])。就我个人而言,我喜欢双等号,因为它让我想起了其他编程语言中的逻辑比较,而双引号只是因为我喜欢打字。所以这些工作:

# With variable set as an integer and evaluating to true/false
# *** These statements will work properly: *****
#
The_world_is_flat=true/false;
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" = true ]]; then
#
if [ "${The_world_is_flat}" = true ]; then
#
if [[ "${The_world_is_flat}" == true ]]; then

你知道了。

博士TL;

my_bool=true

if [ "$my_bool" = true ]

未来音乐(最初)的回答有问题

我不推荐公认的答案。它的语法很漂亮,但也有一些缺陷。

假设我们有以下条件。

if $var; then
  echo 'Muahahaha!'
fi

在以下情况2中,此条件将计算为true并执行嵌套命令。

# Variable var not defined beforehand. Case 1
var=''  # Equivalent to var="".      # Case 2
var=                                 # Case 3
unset var                            # Case 4
var='<some valid command>'           # Case 5

通常,当你的“布尔”变量var显式设置为true时,你只希望你的条件值为true。其他所有的案例都是危险的误导!

最后一种情况(#5)特别淘气,因为它将执行变量中包含的命令(这就是为什么对于有效的command3,4,条件的计算结果为true)。

这里有一个无害的例子:

var='echo this text will be displayed when the condition is evaluated'
if $var; then
  echo 'Muahahaha!'
fi

# Outputs:
# this text will be displayed when the condition is evaluated
# Muahahaha!

引用你的变量是更安全的,例如,if "$var";然后。在上述情况下,您应该得到一个警告,表示没有找到该命令。但我们仍然可以做得更好(见下面我的建议)。

也可以看看Mike Holt对Miku最初答案的解释。

赫巴的回答有问题

这种方法也有意想不到的行为。

var=false
if [ $var ]; then
  echo "This won't print, var is false!"
fi

# Outputs:
# This won't print, var is false!

您可能期望上述条件的值为false,因此永远不会执行嵌套语句。惊喜!

引用值("false"),引用变量("$var"),或者使用test或[[而不是[,都没有区别。

我的建议是:

以下是我建议你检查“布尔值”的方法。他们按照预期工作。

my_bool=true

if [ "$my_bool" = true ]; then
if [ "$my_bool" = "true" ]; then

if [[ "$my_bool" = true ]]; then
if [[ "$my_bool" = "true" ]]; then
if [[ "$my_bool" == true ]]; then
if [[ "$my_bool" == "true" ]]; then

if test "$my_bool" = true; then
if test "$my_bool" = "true"; then

它们几乎都是一样的。与其他答案5中的方法相比,您将不得不输入更多的按键,但您的代码将更具防御性。


脚注

未来音乐的回答已被编辑,不再包含(已知的)缺陷。 这不是一个详尽的清单。 在此上下文中,有效命令是指存在的命令。命令使用正确或不正确并不重要。例如,man woman仍然被认为是一个有效的命令,即使没有这样的手册页存在。 对于无效的(不存在的)命令,Bash只会报错说没有找到该命令。 如果你关心长度,第一个建议是最短的。

下面是if为true的一个实现。

# Function to test if a variable is set to "true"
_if () {
    [ "${1}" == "true" ] && return 0
    [ "${1}" == "True" ] && return 0
    [ "${1}" == "Yes" ] && return 0
    return 1
}

示例1

my_boolean=true

_if ${my_boolean} && {
    echo "True Is True"
} || {
    echo "False Is False"
}

示例2

my_boolean=false
! _if ${my_boolean} && echo "Not True is True"

长话短说:

Bash中没有布尔值

true和false命令

Bash确实有比较和条件方面的布尔表达式。也就是说,在Bash中可以声明和比较的是字符串和数字。就是这样。

无论你在Bash中看到真或假,它要么是一个字符串,要么是一个命令/内置,它只用于退出代码。

这语法…

if true; then ...

本质上是…

if COMMAND; then ...

其中命令为true。当命令返回退出代码0时,条件为真。true和false是Bash内置的,有时也是独立的程序,它们什么都不做,只返回相应的退出码。


条件在if..then..fi

当使用方括号或test命令时,您依赖于该构造的退出代码。请记住,[]和[[]]也像其他命令一样只是命令/内置程序。所以…

if [[ 1 == 1 ]]; then echo yes; fi

对应于

if COMMAND; then echo yes; fi

这里的COMMAND是[[参数为1 == 1]]

如果…那么…Fi构念只是语法糖。你可以用双&号分隔命令来运行同样的效果:

[[ 1 == 1 ]] && echo yes

当在这些测试结构中使用true和false时,您实际上只是将字符串“true”或“false”传递给测试命令。这里有一个例子:

信不信由你,但这些条件都产生了相同的结果:

if [[ false ]]; then ...
if [[ "false" ]]; then ...
if [[ true ]]; then ...
if [[ "true" ]]; then ...

TL,博士;总是与字符串或数字进行比较

为了让未来的读者更清楚地了解这一点,我建议在真假周围使用引号:

DO

if [[ "${var}" == "true" ]]; then ...
if [[ "${var}" == "false" ]]; then ...
if [[ "${var}" == "yes" ]]; then ...
if [[ "${var}" == "USE_FEATURE_X" ]]; then ...
if [[ -n "${var:-}" ]]; then echo "var is not empty" ...

# Always use double square brackets in bash!
if [ ... ]; then ...
# This is not as clear or searchable as -n
if [[ "${var}" ]]; then ...
# Creates impression of Booleans
if [[ "${var}" != true ]]; then ...
# `-eq` is for numbers and doesn't read as easy as `==`
if [[ "${var}" -eq "true" ]]; then ...

也许

# Creates impression of Booleans.
# It can be used for strict checking of dangerous operations.
# This condition is false for anything but the literal string "true".
if [[ "${var}" != "true" ]]; then ... 

这里似乎有一些关于Bash内置true的误解,更具体地说,关于Bash如何展开和解释括号内的表达式的误解。

miku回答中的代码与Bash内置的true,或/bin/true,或任何其他类型的true命令完全无关。在这种情况下,true只不过是一个简单的字符串,并且没有调用true命令/内置,无论是通过变量赋值,还是通过条件表达式求值。

下面的代码在功能上与miku回答中的代码相同:

the_world_is_flat=yeah
if [ "$the_world_is_flat" = yeah ]; then
    echo 'Be careful not to fall off!'
fi

唯一不同的是,这里比较的四个字符是'y'、'e'、'a'和'h',而不是't'、'r'、'u'和'e'。就是这样。在Bash解析令牌true时,没有尝试调用名为yeah的命令或内置命令,(在miku的例子中)也没有任何特殊处理。它只是一个字符串,一个完全任意的字符串。

更新(2014-02-19):在看了miku回答中的链接后,现在我知道困惑来自哪里了。Miku的回答使用了单括号,但他链接的代码片段没有使用括号。它只是:

the_world_is_flat=true
if $the_world_is_flat; then
  echo 'Be careful not to fall off!'
fi

这两个代码段将以相同的方式运行,但括号完全改变了底层的内容。

以下是Bash在每种情况下所做的事情:

没有括号:

将变量$the_world_is_flat展开为字符串“true”。 尝试将字符串“true”解析为命令。 找到并运行true命令(内置或/bin/true,取决于Bash版本)。 比较true命令的退出码(总是0)和0。回想一下,在大多数shell中,退出码为0表示成功,其他任何退出码都表示失败。 因为退出代码是0 (success),所以执行if语句的then子句

括号:

将变量$the_world_is_flat展开为字符串“true”。 解析现在完全展开的条件表达式,其形式为string1 = string2。=操作符是bash的字符串比较操作符。所以… 对"true"和"true"进行字符串比较。 是的,这两个字符串是一样的,所以条件的值为真。 执行if语句的then子句。

不带括号的代码可以工作,因为true命令返回一个退出代码0,表示成功。括号内的代码可以工作,因为$the_world_is_flat的值与=右边的字符串字面量true相同。

为了说明这一点,请考虑以下两段代码:

这段代码(如果以root权限运行)将重启您的计算机:

var=reboot
if $var; then
  echo 'Muahahaha! You are going down!'
fi

这段代码只是打印出“Nice try”。没有调用reboot命令。

var=reboot
if [ $var ]; then
  echo 'Nice try.'
fi

更新(2014-04-14)回答评论中关于=和==的区别的问题:AFAIK,没有区别。==操作符是特定于bash的=的同义词,据我所知,它们在所有上下文中的工作方式完全相同。

但是请注意,我特别讨论的是[]或[[]]测试中使用的=和==字符串比较运算符。我并不是说=和==在bash中到处都可以互换。

例如,你显然不能用==来做变量赋值,比如var=="foo"(技术上你可以这样做,但var的值将是"=foo",因为Bash在这里没有看到==运算符,它看到的是=(赋值)运算符,后面跟着字面值="foo",这就变成了"=foo")。

此外,虽然=和==是可互换的,但您应该记住,这些测试的工作方式取决于您是否在[]或[[]]中使用它,以及操作数是否被引用。您可以在高级Bash脚本指南:7.3其他比较操作符(向下滚动到=和==的讨论)中阅读更多相关内容。