如何在Shell脚本中声明和使用布尔变量?


976

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

variable=$false

variable=$true

它是否正确?另外,如果我想更新该变量,我会使用相同的语法吗?最后,使用布尔变量作为表达式的以下语法正确吗?

if [ $variable ]

if [ !$variable ]

73
谨防! truefalse在大多数片段的上下文中只是普通的字符串,没有bash built-ins!请阅读下面的Mike Holt回答。(这是一个示例,其中投票
最多

7
@mjv对这个问题(和Miku的答案)的大部分困惑是由于Miku在发表了几条评论以描述Miku的答案如何涉及内置的bash 之后在某个时候修改了他的答案true。事实证明,Miku的原始答案确实确实调用了true内置函数,但修改后的答案没有。这导致上述注释似乎对Miku的代码工作方式不正确。此后,对Miku的答案进行了编辑,以明确显示原始代码和修改后的代码。希望这能使混乱一劳永逸。
Mike Holt

2
[ true ] && echo yes, true is true和(upppsss)[ false ] && echo yes, false is also true。/ bin / true和/ bin / false给出返回码$?不用于比较的功能。
fcm

如果VAR设置variable=something比它是真实的,如果取消设置variable=,这将是错误的[[ $variable ]] && echo true || echo false和反向[[ ! $variable ]] && echo false || echo true
伊万

Answers:


1199

修订版答案(2014年2月12日)

the_world_is_flat=true
# ...do something interesting...
if [ "$the_world_is_flat" = true ] ; then
    echo 'Be careful not to fall off!'
fi

原始答案

注意事项:https : //stackoverflow.com/a/21210966/89391

the_world_is_flat=true
# ...do something interesting...
if $the_world_is_flat ; then
    echo 'Be careful not to fall off!'
fi

来自:在Bash中使用布尔变量

之所以在此处包含原始答案,是因为2014年2月12日修订之前的评论仅与原始答案有关,并且许多评论与修订后的答案相关时都是错误的。例如,丹尼斯·威廉姆森(Dennis Williamson)true在2010年6月2日对内置bash的评论仅适用于原始答案,而不适用于修订版。


37
解释发生了什么:if语句正在执行Bash内置变量的内容true。可以将任何命令设置为变量的值,并将评估其退出值。
暂停,直到另行通知。

7
@pms运算符“ -o”和“ -a”仅用于“ test”命令(又名“ []”)。相反,这是“ if +命令”,而没有“测试”。(例如,“如果是grep foo文件,则为...”。)因此,请使用normal &&||运算符:# t1=true; t2=true; f1=false;if $t1 || $f1; then echo is_true ; else echo is_false; fi; (由于t1 = true,返回“ true”)if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi (由于t2 = true,返回“ true”)。同样,这仅适用,因为“ true” /“ false”是bash-buildins(返回true / false)。除非var是cmd(即对或错),否则您不能使用“ if $ var ...”
michael 2012年

14
-1,请参阅我的答案以获取解释。
丹尼斯

3
许多错误信息,在这里。/ bin / true没有得到有效使用。参见丹尼斯的答案。
2014年

1
此代码不同,并且与链接文章的工作方式不同。链接的代码通过存储在变量中的名称来调用程序,但是此答案中的代码只是字符串比较。
Quolonel问题

794

TL; DR

bool=true

if [ "$bool" = true ]

有三苦的(问题)答案

推荐接受的答案1。它的语法很漂亮,但是有一些缺陷。

说我们有以下情况。

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)尤其顽皮,因为它将执行变量中包含的命令(这就是为什么条件对有效命令3、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"; then。在上述情况下,您应该得到一条警告,提示找不到该命令。但是我们仍然可以做得更好(请参阅底部的建议)。

另请参阅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[[代替[并没有什么不同。

建议:

我建议您通过以下方法检查“布尔值”。他们按预期工作。

bool=true

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

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

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

它们几乎相等。您将需要比其他答案5中的方法键入更多的击键,但是您的代码将更具防御性。


脚注

  1. 此后,Miku的答案已被编辑,不再包含(已知)缺陷。
  2. 并非详尽的清单。
  3. 在此上下文中,有效命令表示存在的命令。命令的使用正确与否无关紧要。例如man woman,即使不存在这样的手册页,它也仍然被视为有效命令。
  4. 对于无效(不存在)的命令,Bash只会抱怨找不到该命令。
  5. 如果您在意长度,则第一个建议是最短的。

8
使用==具有[test不具有可移植性。考虑到便携性是唯一的优势[/ test已经[[坚持不懈=
chepner 2014年

2
@Scott我以fish为主要外壳,与bash相比,它具有健全的脚本语言。
丹尼斯

1
是的,我只是在评论中找不到对此隐藏的笑话的任何赞赏,因此必须指出=)
Kranach

5
对于我来说,如果使用bool =“ true”,从概念上更容易理解。然后很明显,它只是一个字符串,而不是一些特殊值或内置值。
wisbucky 2015年

1
@dolmen绝对是,在您控制输入时评估输入没有那么冒险,但是我仍然认为这是一种不好的做法,如果可以轻松避免,则应该避免。曾经只看过并使用过前一种样式的人可能不知道其可能导致意外行为的缺陷。
丹尼斯

175

关于Bash内置函数true,尤其是关于Bash如何扩展和解释方括号内的表达式,这里似乎存在一些误解。

miku的答案中的代码与内置的Bash true,nor /bin/truetrue命令的任何其他形式完全无关。在这种情况下,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”。而已。yeah在Bash解析令牌时,没有尝试调用名为named的命令或内置命令,也没有进行任何形式的特殊处理(在miku的示例中)true。它只是一个字符串,并且完全是任意的。

更新(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在每种情况下所做的事情:

没有括号:

  1. 将变量$the_world_is_flat扩展为字符串"true"
  2. 尝试将字符串解析"true"为命令。
  3. 查找并运行true命令(内置命令或/bin/true,具体取决于Bash版本)。
  4. true命令的退出代码(始终为0)与0进行比较。回想一下,在大多数shell中,退出代码0表示成功,而其他任何代码则表示失败。
  5. 由于退出代码为0(成功),因此执行if语句的then子句

括号:

  1. 将变量$the_world_is_flat扩展为字符串"true"
  2. 解析现在已完全扩展的条件表达式,其形式为string1 = string2。该=运算符是bash的字符串比较运算符。所以...
  3. "true"和上进行字符串比较"true"
  4. 是的,两个字符串相同,所以条件的值是true。
  5. 执行if语句的then子句。

无括号代码有效,因为该true命令返回的退出代码为0,表示成功。括号内的代码有效,因为的值$the_world_is_flattrue右侧的字符串文字相同=

只是为了说明问题,请考虑以下两个代码段:

此代码(如果以root特权运行)将重新引导计算机:

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

此代码仅显示“ Nice try”。重新启动命令不被调用。

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

更新(2014年4月14日)要回答在评论有关之间的差异问题===:据我所知,没有任何区别。该==运营商是一个Bash的专用代名词=,而据我所看到的,他们的工作在所有情况完全一样。

但是请注意,我是专门谈论在或测试中使用的===字符串比较运算符。我不建议这样做,并且在bash中到处都是可以互换的。[ ][[ ]]===

例如,您显然不能使用进行变量赋值==,例如var=="foo"(从技术上讲,您可以这样做,但是varwill 的值是"=foo",因为Bash ==在这里没有看到运算符,而是看到了=(赋值)运算符,然后是文字值="foo",变成"=foo")。

另外,尽管===可以互换,但是您应该记住,这些测试的工作方式确实取决于您是在[ ]还是内部使用它[[ ]],还取决于操作数是否被引用。你可以阅读更多有关在高级Bash脚本编程指南:7.3其他比较操作符(向下滚动到的讨论===)。


不用括号的方法还具有让您编写干净,清晰(imo)的单行代码的优势,例如$the_world_is_flat && echo "you are in flatland!"
ajk 2014年

9
真正。虽然,我并不主张(或反对)任何一种方法。我只是想清理一些在这里被投票否定的错误信息,这样以后就迷失于此主题的人们就不会对这一切的工作产生误解。
Mike Holt 2014年

1
造成这种混乱的原因是,miku最初的回答持续了4年。所有true关于内建函数的参考都是关于原始答案的。(2014年2月12日修订的答案不是miku提交的。)我已经编辑了答案,以包含原始答案和经修订的答案。人们的评论才有意义。
wisbucky

1
通过阅读此处提供的答案,我得到的印象是,没有真正使用real的东西true。有办法吗?我怀疑许多习惯于使用更严格的语言查看这些答案以帮助他们混合一些bash胶水以使生活更轻松的程序员会想要一个===运算符,以使字符串和“布尔值”实际上不可互换。如果他们只是坚持0,1和使用(( $maybeIAmTrue ))作为建议Quolonel问题答案
SeldomNeedy

2
要解决SeldomNeedy的评论,是的,您可以使用real true,但通常不能将其与变量进行比较,因为real true本身没有任何价值。它所做的一切只是将退出状态设置为0,表示成功。值得注意的是,它本质上等效于所谓的“空命令”或:。至于使用0and 1,这就是我最近需要布尔值的所有脚本的工作。我使用(( ))运算符而不是[[ ]]求值。因此,例如,如果我有flag=0,那么我可以做if (( flag )); then ...
Mike Holt

57

使用算术表达式。

#!/bin/bash

false=0
true=1

((false)) && echo false
((true)) && echo true
((!false)) && echo not false
((!true)) && echo not true

输出:


不是假


3
优点:(1.)行为与C处理布尔值的方式类似;(2。)语法非常简洁/最小(不需要右手变量,并且不需要运算符,例如'='或'=='),(3 。)<主观>对我来说,我理解没有冗长的解释会发生什么...与Miku和Dennis的答案似乎都需要冗长的解释形成对比</ subjective>
Trevor Boyd Smith

3
@TrevorBoydSmith为什么你不只是说:“优点:一切,缺点:没事”。从长远来看,可以节省键盘和显示器的折旧费用。
Quolonel问题

4
对于交互式使用(例如单线),请确保在后面留一个空格!,否则它将扩展历史记录。 ((! foo))作品,也是如此! ((foo))。我喜欢这个解决方案,顺便说一句。最后是一种执行布尔变量的简洁方法。 ((foo || bar))可以正常工作。
彼得·科德斯

5
(())递归地扩展变量,这没想到。 foo=bar; bar=baz; ((foo)) && echo echo什么都不会打印,但使用确实如此baz=1。因此,您可以通过来支持foo=truefoo=false以及0或1 true=1
彼得·科德斯

2
@quolonel感谢您提供的非常有用的资源。当然,我的理解是有限的-无论领域如何,所有理解都受到限制是人的天性。但是,您介意告诉我,我的哪项陈述使您假设我对这一特定问题的理解不完整?
Hubert Grzeskowiak

34

长话短说:

Bash中没有布尔值

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

无论您在哪里看到Bash truefalse在Bash中,它都是字符串或仅用于退出代码的命令/内置。

这个语法...

if true; then ...

本质上是...

if COMMAND; then ...

只要命令返回退出代码0 true,该条件为true,并且false是Bash内置函数,有时甚至是独立的程序,除了返回相应的退出代码之外,它们什么也不做。

上面的条件等同于:

COMMAND && ...

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

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

对应于

if COMMAND; then echo yes; fi

COMMAND这里是[[ 1 == 1 ]]

if..then..fi构造只是语法糖。您始终可以只运行用双“&”号分隔的命令,以达到相同的效果:

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

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

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

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

TL; DR; 始终与字符串或数字进行比较

为了使将来的读者清楚知道,我建议始终在true和周围使用引号false

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

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

也许

if [[ "${var}" != "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".

我更喜欢使用TF明确指出这些不是真正的布尔值。
phk

1
我不同意“总是在bash中使用双括号”。实际上,在我编写的几乎所有脚本中,我都使用单括号,除非需要进行模式匹配。我认为一个人应该了解[test和)之间的区别,[[并使用适合其需要的一个。
周伟俊

@WeijunZhou介意在哪种情况下使用单括号更好?
Hubert Grzeskowiak,

它更像是一种个人品味,我只是发现说“总是在bash中使用双方括号”实在太大胆了。但是我使用了一些极端情况。单括号使您可以在变量中指定测试本身。作为一个过于简单的示例,请考虑if ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
周卫军,

@WeijunZhou您的示例强烈反对单个方括号。它使代码更难理解,并打开了容易出错的窗口。双括号更加严格,并鼓励使用更简洁的代码。
休伯特·格热斯科维克

18

很久以前,当我们只有sh布尔值时,将依靠test程序的约定对布尔值进行处理,test如果不带任何参数运行,则返回错误的退出状态。

这样一来,您就可以想到未设置为false且将任何值设置为true的变量。今天,它test是Bash的内置函数,并且通常以其一个字符的别名而闻名[(或者像dolmen所指出的那样,是在缺少它的shell中使用的可执行文件):

FLAG="up or <set>"

if [ "$FLAG" ] ; then
    echo 'Is true'
else
    echo 'Is false'
fi

# Unset FLAG
#    also works
FLAG=

if [ "$FLAG" ] ; then
    echo 'Continues true'
else
    echo 'Turned false'
fi

由于使用了引号约定,脚本编写者更喜欢使用[[模仿的复合命令test,但语法更好:可以使用具有奇怪优先级的&&||作为逻辑运算符,并且POSIX对术语数没有限制。

例如,确定是否设置了FLAG并且COUNT是大于1的数字:

FLAG="u p"
COUNT=3

if [[ $FLAG  && $COUNT -gt '1' ]] ; then
    echo 'Flag up, count bigger than 1'
else
    echo 'Nope'
fi

当都需要空格,零长度字符串和空变量时,以及当脚本需要使用多个shell时,这些东西可能会造成混乱


3
[不只是内部的别名bash。该别名也以二进制文件(或指向的链接)的形式存在,并且可以与裸机一起使用sh。检查ls -l /usr/bin/\[。使用bash/,zsh您应该改为使用[[真正的纯内部函数,并且功能更强大。
支石墓

1
@dolmen [并且test也是一个bash shell的内置命令根据猛砸手册页,所以应该不会有性能问题。与Dash相同。(/ bin / sh可能只是到/ bin / dash的符号链接)。要使用可执行文件,您必须使用完整路径,即 /usr/bin/\[
jarno

12

如何在Shell脚本中声明和使用布尔变量?

与许多其他编程语言不同,Bash不会按“类型”分隔其变量。[1]

因此答案很明确。Bash中没有任何布尔变量

然而:

使用声明语句,我们可以将值分配限制为变量。[2]

#!/bin/bash
declare -ir BOOL=(0 1) # Remember BOOL can't be unset till this shell terminates
readonly false=${BOOL[0]}
readonly true=${BOOL[1]}

# Same as declare -ir false=0 true=1
((true)) && echo "True"
((false)) && echo "False"
((!true)) && echo "Not True"
((!false)) && echo "Not false"

r选件declarereadonly用于国家明确的变量是只读的。我希望目的很明确。


1
你为什么不做declare -ir false=0 true=1呢?使用数组的好处是什么?
本杰明·W.

@BenjaminW。我只想提及r选项和readonly命令。我会按照您在脚本中建议的方式进行操作
sjsam '16

也许我错过了一些东西,但是为什么不以这种方式声明的true和false使用美元符号呢?$ true $ false
qodeninja

从字面上看只是复制我的答案,并使它变得更糟。
Quolonel问题,

@QuolonelQuestions Bash变量没有类型化,因此没有必要说declare and use boolean variables。我们可以通过多种方式模仿/假设变量具有 类型。我没有在您的答案中提到任何地方。
sjsam

10

为什么不假装布尔值并为将来的读者留下陷阱,为什么不使用比true和false更好的值呢?

例如:

build_state=success
if something-horrible; then
  build_state=failed
fi

if [[ "$build_state" == success ]]; then
  echo go home; you are done
else
  echo your head is on fire; run around in circles
fi

为什么不整数?
phil294

3
@Blauhirn,因为整数根据语言使用的方式有所不同。在一些语言0胁迫到false1true。关于程序退出代码(bash过去使用的代码)是0为了取得积极的结果,或者true其他一切都是负面/错误或false
Hubert Grzeskowiak

7

POSIX(便携式操作系统接口)

我在这里想念关键点,那就是可移植性。这就是我的标头本身具有POSIX的原因。

本质上,所有投票的答案都是正确的,除了它们是特定于Bash的过多之外。

基本上,我只希望添加有关可移植性的更多信息。


  1. []in之[ "$var" = true ]类的括号不是必需的,您可以忽略它们并test直接使用命令:

    test "$var" = true && yourCodeIfTrue || yourCodeIfFalse

    重要说明:我不建议您这样做,因为它已逐渐被弃用,并且难以合并多个语句。

  2. 想象一下那些话true,并false指到外壳,测试自己:

    echo $(( true ))
    0
    echo $(( false ))
    1

    但是使用引号:

    echo $(( "true" ))
    bash: "true": syntax error: operand expected (error token is ""true"")
    sh (dash): sh: 1: arithmetic expression: expecting primary: ""true""

    同样适用于:

    echo $(( "false" ))

    除了字符串,shell无法解释它。希望您能想到使用不带引号的适当关键字的效果如何。

    但是没有人在先前的回答中说过。

  3. 这是什么意思?好吧,几件事。

    • 您应该习惯了Boolean关键字实际上被当作数字对待,即true= 0false= 1,请记住所有非零值都被视为false

    • 由于将它们视为数字,因此您也应该将它们视为数字,即,如果定义变量,请说:

      var_bool=true
      echo "$var_bool"
       true

      您可以使用以下方法创建相反的值:

      var_bool=$(( 1 - $var_bool ))  # same as $(( ! $var_bool ))
      echo "$var_bool"
      1

    如您所见,shell true第一次使用时会打印字符串,但是从那时起,它都分别通过数字0表示true1表示来false工作。


最后,您应该如何处理所有这些信息

  • 首先,一个好的习惯是分配0而不是true1代替false

  • 第二个好习惯是测试变量是否为/不等于零:

    if [ "$var_bool" -eq 0 ]; then
         yourCodeIfTrue
    else
         yourCodeIfFalse
    fi

6

关于语法,这是一种简单的方法,我使用(以示例方式)一致且明智地管理布尔逻辑:

# 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=''

参考:

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

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


5

在许多编程语言中,布尔类型是整数或被实现为整数的子类型,其true行为类似于1false行为如下0

在数学上,布尔代数类似于2的整数算术运算。因此,如果语言不提供本机布尔类型,则最自然和有效的解决方案是使用整数。这几乎适用于任何语言。例如,在Bash中,您可以执行以下操作:

# val=1; ((val)) && echo "true" || echo "false"
true
# val=0; ((val)) && echo "true" || echo "false"
false

男人的bash

((表达))

根据以下算术评估中所述的规则评估表达式。如果表达式的值不为零,则返回状态为0;否则,返回值为0。否则返回状态为1。这完全等同于let“表达式”。


5

Bill Parker被否决了,因为他的定义与常规代码约定相反。通常,将true定义为0,将false定义为非零。1代表false,9999和-1代表false。函数返回值相同-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真]] =成功,但也评估为[[0 -eq真]] =成功,这是错误的(嗯,内建值是数字吗?)。

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

条件的其他排列也会产生错误的输出。基本上,任何将变量设置为数值并将其与true / false内置参数进行比较,或将变量设置为true / false内置参数并将其与数值进行比较的东西(上述错误条件除外)。同样,将变量设置为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

所以,现在要做什么。在比较和评估中都使用true / false内置函数(如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

你有它。


2
true/ false内置插件这里没有使用(忽略什么语法高亮部分的编辑可能暗示),尤其是在[…]情况下,你可以把它作为一个简单的字符串这里(一个是作为参数的[命令)。
phk

你现在有。
Peter Mortensen

4

我的发现和建议与其他帖子有所不同。我发现我基本上可以像在任何“常规”语言中一样使用“布尔值”,而无需建议“跳圈”。

不需要进行任何[]显式的字符串比较...我尝试了多个Linux发行版。我测试了Bash,Dash和BusyBox。结果总是一样的。我不确定最初被投票最多的帖子在谈论什么。也许时代已经改变,仅此而已?

如果将变量设置为true,则它随后在条件中被评估为“肯定”。将其设置为false,其结果为“负”。非常简单!唯一的警告是,一个未定义的变量的求值也像true!如果这样做相反(这在大多数语言中也是如此)会很好,但这就是窍门- 您只需将布尔值显式初始化为true或false即可

为什么这样工作?这个答案有两个方面。A)shell中的true / false真正表示“无错误”与“错误”(即0与其他任何东西)。B)true / false不是值-而是shell脚本中的语句!关于第二点,执行truefalse在线执行本身false会将您所在的块的返回值设置为该值,即是“遇到错误”的声明,其中真正的“清除”了该错误。将其与变量分配一起使用会将其“返回”到变量中。一个未定义的变量计算像true在条件,因为同样表示0或“没有遇到错误”。

请参阅下面的示例Bash行和结果。如果要确认,请自行测试...

#!/bin/sh

# Not yet defined...
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=true
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

myBool=false
echo "when set to ${myBool}"
if ${myBool}; then echo "it evaluates to true"; else echo "it evaluates to false"; fi;

产量

when set to
it evaluates to true
when set to true
it evaluates to true
when set to false
it evaluates to false

1

这是一个对我有用的简单示例:

temp1=true
temp2=false

if [ "$temp1" = true ] || [ "$temp2" = true ]
then
    echo "Do something." 
else
    echo "Do something else."
fi

1

这是一个捷径的实现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"

是的,功能分解被低估了。
Peter Mortensen

1

我发现现有的答案令人困惑。

就个人而言,我只想拥有外观和工作原理类似于C的东西。

此代码段每天在生产中工作多次:

snapshotEvents=true

if ($snapshotEvents)
then
    # Do stuff if true
fi

为了让所有人开心,我测试了:

snapshotEvents=false

if !($snapshotEvents)
then
    # Do stuff if false
fi

这也很好。

所述$snapshotEvents评估的变量的值的内容。所以你需要$

您实际上并不需要括号,我只是觉得它们很有帮助。

  • 测试于:GNU Bash版本4.1.11(2)-发行版

  • Bash初学者指南,Machtelt Garrels,v1.11,2008年


2
在删除括号的地方,这恰好是@miku在顶部的原始答案。
2016年

1
没有括号的表达式不计算。
将于

@将是的。您不需要()。
phil294

1
@Blauhirn ...嗨,我的评论基于Linux Mint / Ubuntu PC上的GNU Bash实验。理论上 您可能是正确的- ()不需要。我唯一的回答就是尝试一下,它似乎取决于 Bash版本,实际的表达式或上下文等。
将于

1

这是miku 最初答案的一个改进,解决了Dennis Williamson对未设置变量的情况的担忧:

the_world_is_flat=true

if ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

并测试变量是否为false

if ! ${the_world_is_flat:-false} ; then
    echo "Be careful not to fall off!"
fi

对于在变量中包含讨厌内容的其他情况,这是将任何外部输入馈送到程序的问题。

在信任任何外部输入之前,必须先对其进行验证。但是,当收到该输入时,验证仅需执行一次。

不必像Dennis Williamson所建议的那样,通过对变量的每次使用来影响程序的性能。


1

您可以使用shFlags

它为您提供了定义的选项: DEFINE_bool

例:

DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");

在命令行中,您可以定义:

sh script.sh --bigmenu
sh script.sh --nobigmenu # False

GFlags在这个答案中没有任何意义-它是一个C ++库。它不能直接在shell脚本中使用。
乔纳森·克罗斯

更新了对shFlags的响应,它是GFlags移植到shell的端口。
gogasca

0

这是关于在Bash中测试“布尔”值的不同方法的速度测试:

#!/bin/bash
rounds=100000

b=true # For true; b=false for false
type -a true
time for i in $(seq $rounds); do command $b; done
time for i in $(seq $rounds); do $b; done
time for i in $(seq $rounds); do [ "$b" == true ]; done
time for i in $(seq $rounds); do test "$b" == true; done
time for i in $(seq $rounds); do [[ $b == true ]]; done

b=x; # Or any non-null string for true; b='' for false
time for i in $(seq $rounds); do [ "$b" ]; done
time for i in $(seq $rounds); do [[ $b ]]; done

b=1 # Or any non-zero integer for true; b=0 for false
time for i in $(seq $rounds); do ((b)); done

它会打印类似

true is a shell builtin
true is /bin/true

real    0m0,815s
user    0m0,767s
sys     0m0,029s

real    0m0,562s
user    0m0,509s
sys     0m0,022s

real    0m0,829s
user    0m0,782s
sys     0m0,008s

real    0m0,782s
user    0m0,730s
sys     0m0,015s

real    0m0,402s
user    0m0,391s
sys     0m0,006s

real    0m0,668s
user    0m0,633s
sys     0m0,008s

real    0m0,344s
user    0m0,311s
sys     0m0,016s

real    0m0,367s
user    0m0,347s
sys     0m0,017s

-2

替代方法-使用功能

is_ok(){ :;}
is_ok(){ return 1;}
is_ok && echo "It's OK" || echo "Something's wrong"

定义函数不太直观,但是检查其返回值非常容易。


1
这不是您可以测试的变量,而是常量函数
jarno

@jarno就脚本而言,测试函数的返回值是否不同于测试变量?
johnraff '19

好吧,问题在于变量。
jarno

是的,尽管外壳程序脚本中的用法是相同的。
johnraff '19

-2

猛砸真的会混淆事实与这样的人[[[(($((,等。

所有人都踩着彼此的代码空间。我猜这主要是历史性的,Bash不得不假装是sh偶然的。

大多数时候,我只能选择一种方法并坚持使用。在这种情况下,我倾向于声明(最好在我可以包含.在实际脚本中的公共库文件中)。

TRUE=1; FALSE=0

然后,我可以使用((... ))算术运算符进行测试。

testvar=$FALSE

if [[ -d ${does_directory_exist} ]]
then
    testvar=$TRUE;
fi

if (( testvar == TRUE )); then
    # Do stuff because the directory does exist
fi
  1. 您必须受到纪律处分。您testvar必须始终设置为$TRUE$FALSE

  2. ((... ))比较器中,不需要前面的$,这使它更具可读性。

  3. 我可以使用((...,))因为$TRUE=1$FALSE=0,即数值。

  4. 缺点是必须$偶尔使用:

    testvar=$TRUE

    不太漂亮

这不是一个完美的解决方案,但是它涵盖了我需要进行此类测试的所有情况。


2
您应该将常量声明为只读。另外,使用变量时请始终使用大括号。每个人都应该遵守恕我直言的惯例。该解决方案的一大缺点是您不能将代数表达式与测试标志或字符串比较混合使用。
Hubert Grzeskowiak
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.