【问题标题】:How can I declare and use Boolean variables in a shell script?如何在 shell 脚本中声明和使用布尔变量?
【发布时间】:2011-02-26 13:46:42
【问题描述】:

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]

【问题讨论】:

    标签: bash shell scripting boolean sh


    【解决方案1】:

    修订后的答案(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
    

    发件人:Using boolean variables in Bash

    此处包含原始答案的原因是因为 2014 年 2 月 12 日修订之前的 cmets 仅与原始答案相关,而与修订后的答案相关联时,许多 cmets 是错误的。例如,Dennis Williamson 在 2010 年 6 月 2 日关于 bash builtin true 的评论仅适用于原始答案,不适用于修订版。

    【讨论】:

    • 解释发生了什么:if 语句正在执行 Bash 内置变量 true 的内容。任何命令都可以设置为变量的值,并评估其退出值。
    • @pms 运算符“-o”和“-a”仅用于“test”命令(又名“[]”)。相反,这是“if + command”,没有“test”。 (比如“if grep foo file; then ...”。)所以,使用普通的 &&|| 运算符:# t1=true; t2=true; f1=false; # if $t1 || $f1; then echo is_true ; else echo is_false; fi; (返回“true”,因为 t1=true) # if $t1 && $f1 || $t2; then echo is_true ; else echo is_false; fi (返回“true”,因为 t2=true) 。同样,这仅有效,因为“true”/“false”是 bash-builtins(返回 true/false)。你不能使用 "if $var..." 除非 var 是一个 cmd(即 true 或 false)
    • -1, see my answer 进行解释。
    • 这里有很多不正确的信息。 /bin/true 没有被有效使用。请参阅丹尼斯的回答。
    • 此代码与链接文章不同,其工作方式也不同。链接代码通过存储在变量中的名称调用程序,但此答案中的代码只是字符串比较。
    【解决方案2】:

    TL;DR

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

    Miku (original) 回答的问题

    我确实推荐接受的答案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条件评估为真的原因)。

    这是一个无害的例子:

    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。在上述情况下,您应该会收到未找到该命令的警告。但我们仍然可以做得更好(见底部我的建议)。

    Also see Mike Holt's explanation of Miku's original answer.

    Hbar's answer 的问题

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

    var=false
    if [ $var ]; then
      echo "This won't print, var is false!"
    fi
    
    # Outputs:
    # This won't print, var is 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,但您的代码将更具防御性。


    脚注

    1. Miku 的答案已被编辑,不再包含(已知)缺陷。
    2. 并非详尽的列表。
    3. 此上下文中的有效命令表示存在的命令。正确或错误地使用命令都没有关系。例如。 man woman 仍将被视为有效命令,即使不存在此类手册页。
    4. 对于无效(不存在)的命令,Bash 只会抱怨找不到该命令。
    5. 如果您关心长度,第一个建议是最短的。

    【讨论】:

    • ==[test 一起使用是不可移植的。考虑到便携性是[/test 超过[[ 的唯一优势,坚持使用=
    • @Scott 我使用fish 作为我的主要 shell,在我看来,与 bash 相比,它的脚本语言更加健全。
    • 是的,我只是在 cmets 中找不到对这个隐藏笑话的任何欣赏,所以不得不指出它 =)
    • 对我来说,从概念上讲,如果我使用 bool="true" 会更容易理解。那么很明显它只是一个字符串,而不是一些特殊的值或内置的。
    • @dolmen 绝对,当您控制输入时,评估输入并没有那么冒险,但我仍然认为这是一种不好的做法,如果可以轻松避免,应该避免。只见过和使用过前一种风格的人可能不知道它的缺陷可能导致意外行为。
    【解决方案3】:

    这里似乎对 Bash 内置函数 true 存在一些误解,更具体地说,是关于 Bash 如何扩展和解释括号内的表达式。

    miku's answer 中的代码与 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 的答案使用单括号,但他链接到的代码 sn-p 不使用括号。只是:

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

    两个代码 sn-ps 将表现相同,但括号完全改变了引擎盖下发生的事情。

    这是 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. 是的,两个字符串相同,所以条件的值为真。
    5. 执行if 语句的then 子句。

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

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

    此代码(如果以 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) 回答 cmets 中关于 === 之间区别的问题:AFAIK,没有区别。 == 运算符是 = 的 Bash 特定同义词,据我所知,它们在所有上下文中的工作方式完全相同。

    但是请注意,我专门讨论的是[ ][[ ]] 测试中使用的=== 字符串比较运算符。我并不是说 === 在 bash 中在任何地方都可以互换。

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

    此外,虽然=== 可以互换,但您应该记住,这些测试的工作方式确实取决于您是在[ ] 还是[[ ]] 中使用它,以及是否引用了操作数。您可以在 Advanced Bash Scripting Guide: 7.3 Other Comparison Operators 中了解更多相关信息(向下滚动到 === 的讨论)。

    【讨论】:

    • 无括号方法还具有让您编写干净、清晰 (imo) 的单行代码的优势,例如 $the_world_is_flat &amp;&amp; echo "you are in flatland!"
    • 是的。虽然,我不提倡(或反对)这两种方法。我只是想澄清一些在这里被投票赞成的错误信息,这样以后偶然发现这个话题的人就不会对这一切如何运作产生一堆误解。
    • 混淆的原因是miku的原始答案保留了4年。所有对内置 true 的引用都是关于原始答案的。 (2014 年 2 月 12 日的修订答案不是 miku 提交的。)我已经编辑了答案以包括原始和修订。那么人们的 cmets 就有意义了。
    • 通过阅读此处提供的答案,我得到的印象是没有真正使用真正的true。有办法吗?我怀疑许多习惯于更严格的语言的程序员查看此答案以帮助他们混合一些 bash 胶水以使他们的生活更轻松一些会想要一个 === 运算符,以便字符串和“布尔值”实际上不能互换.他们是否应该按照Quolonel Questionanswer 中的建议坚持使用0 和1 并使用(( $maybeIAmTrue ))
    • 为了解决 SeldomNeedy 的评论,是的,您可以使用真实的 true,但通常不作为比较变量的对象,因为真实的 true 本身没有任何价值。它所做的只是将退出状态设置为0,表示成功。值得注意的是,它本质上等同于所谓的“空命令”,即:。至于使用01,这就是我这些天在我需要布尔值的所有脚本中所做的。我使用(( )) 运算符而不是[[ ]] 进行评估。所以,例如,如果我有flag=0,那么我可以做if (( flag )); then ...
    【解决方案4】:

    使用算术表达式。

    #!/bin/bash
    
    false=0
    true=1
    
    ((false)) && echo false
    ((true)) && echo true
    ((!false)) && echo not false
    ((!true)) && echo not true
    

    输出:

    是的
    不假

    【讨论】:

    • 优点:(1.) 行为类似于 C 处理布尔值的方式,(2.) 语法非常简洁/最少(不需要右手变量和运算符,如 '=' 或'=='), (3.) 对我来说,如果没有冗长的解释,我明白会发生什么……与 Miku 和 Dennis 的答案形成鲜明对比,这两个答案似乎都需要冗长的解释
    • @TrevorBoydSmith 你为什么不直接说,“优点:一切,缺点:什么都没有”。从长远来看,可以节省键盘和显示器的折旧成本。
    • 对于交互使用,比如单行,一定要在!后面留一个空格,否则会做历史扩展。 ((! foo)) 有效,! ((foo)) 也有效。我喜欢这个解决方案,顺便说一句。最后一个简洁的方法来做布尔变量。 ((foo || bar)) 按预期工作。
    • (()) 递归地扩展变量,这是我没想到的。 foo=bar; bar=baz; ((foo)) &amp;&amp; echo echo 什么也不打印,但 baz=1 是这样。所以你可以通过true=1来支持foo=truefoo=false以及0或1。
    • @wjandrea 这与问题相反,因为现在您有了一种机制来识别代码中的错误。
    【解决方案5】:

    长话短说:

    Bash 中没有布尔值

    truefalse 命令

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

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

    这个语法...

    if true; then ...
    

    本质上是……

    if COMMAND; then ...
    

    命令是true。只要命令返回退出代码 0,条件就为真。truefalse 是 Bash 内置程序,有时也是独立程序,除了返回相应的退出代码之外什么都不做。


    if..then..fi 中的条件

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

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

    对应

    if COMMAND; then echo yes; fi
    

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

    if..then..fi 结构只是语法糖。您始终可以只运行由双 & 号分隔的命令以获得相同的效果:

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

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

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

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

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

    为了让未来的读者明白这一点,我建议始终在 truefalse 周围使用引号:

    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 ... 
    

    【讨论】:

    • 我更喜欢使用 TF 来明确这些不是真正的布尔值。
    • 我不能同意“在 bash 中总是使用双括号”。事实上,在我编写的几乎所有脚本中,我都使用单括号,除非我需要进行模式匹配。我认为人们应该了解[(即test)和[[之间的区别,并使用适合他需要的那个。
    • @WeijunZhou 介意在哪些情况下单括号更好?
    • 更多的是个人口味,我只是觉得说“总是在bash中使用双方括号”太大胆了。但是我使用了一些边缘情况。单括号允许您在 var 中指定测试本身。作为一个过于简单的例子,考虑if ....; then mytest='-gt'; else mytest='-eq'; fi; #several lines of code; if [ "$var1" "$mytest" "$var2" ]; then ...; fi
    • @WeijunZhou 你的例子是反对单方括号的有力论据。它使代码更难理解,并打开了错误的窗口。双括号更严格,并鼓励更简洁的代码。
    【解决方案6】:

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

    这允许人们将未设置为假的变量和设置为任何值的变量视为真。今天,test 是 Bash 的内置函数,通常以其单字符别名 [(或在缺少它的 shell 中使用的可执行文件,如 dolmen 所述)而闻名:

    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 的复合命令[[,但语法更好:带空格的变量不需要引用;可以使用 &amp;&amp;|| 作为具有奇怪优先级的逻辑运算符,并且对术语的数量没有 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
    

    This stuff can get confusing 当所有需要空格、零长度字符串和空变量时,以及当您的脚本需要使用多个 shell 时。

    【讨论】:

    • [ 不仅仅是bash 中的别名。此别名也作为二进制文件(或作为指向的链接)存在,并且可以与裸 sh 一起使用。检查ls -l /usr/bin/\[。使用bash/zsh,您应该改用[[,它是真正的纯内部并且更强大。
    • @dolmen [test 根据 Bash 手册页也是 Bash SHELL BUILTIN COMMAND,因此性能应该没有问题。与例如相同的事情短跑。 (/bin/sh 可能只是 /bin/dash 的符号链接)。要使用可执行文件,您必须使用完整路径,即/usr/bin/\[
    【解决方案7】:

    如何在 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"
    

    declarereadonly 中的r 选项用于明确声明变量是只读。我希望目的很明确。

    【讨论】:

    • 你为什么不直接做declare -ir false=0 true=1?使用数组有什么好处?
    • @BenjaminW。我只是想提一下r 选项和readonly 命令。我会按照你在我的脚本中建议的方式来做
    • 也许我遗漏了一些东西,但为什么不使用美元符号以这种方式声明真假? $true $false
    • 实际上只是复制我的答案并使其变得更糟。
    • @QuolonelQuestions Bash 变量没有类型化,因此说declare and use boolean variables 毫无意义。我们可以不止一种方式模仿/假设一个变量有一个类型。我没有在您的回答中看到任何地方提到这一点。
    【解决方案8】:

    与其伪造布尔值并为未来的读者留下陷阱,为什么不使用比真假更好的值呢?

    例如:

    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
    

    【讨论】:

    • 为什么不用整数?
    • @Blauhirn 因为整数的使用因语言而异。在某些语言中,0 强制转换为 false1 转换为 true。关于程序退出代码(bash 历史上使用的),0 表示积极结果或true,其他一切都是消极/错误或false
    【解决方案9】:

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

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

    如果您将变量设置为true,它随后会在条件中评估为“肯定”。将其设置为false,它的评估结果为“否定”。很直接!唯一需要注意的是,undefined 变量的计算结果也类似于 true!如果它做相反的事情会很好(就像在大多数语言中那样),但这就是诀窍 - 您只需将布尔值显式初始化为 true 或 false

    为什么会这样?这个答案是双重的。 A)外壳中的真/假实际上意味着“无错误”与“错误”(即0与其他任何东西)。 B) true/false 不是值 - 而是 shell 脚本中的 statements!关于第二点,单独在一行上执行truefalse 会将您所在块的返回值设置为该值,即false 是“遇到错误”的声明,其中true“清除“ 那。将其与对变量的赋值一起使用会将其“返回”到变量中。 undefined 变量的计算结果类似于条件中的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
    

    【讨论】:

      【解决方案10】:

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

      Mathematically,布尔代数类似于模2的整数运算。因此,如果一种语言不提供本机布尔类型,最自然和最有效的解决方案是使用整数。这几乎适用于任何语言。例如,在 Bash 中你可以这样做:

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

      man bash:

      ((表达式))

      表达式根据下面算术评估中描述的规则进行评估。如果表达式的值为非零,则返回状态为0;否则返回状态为 1。这完全等价于 let "expression"。

      【讨论】:

        【解决方案11】:

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

        我在这里错过了关键点,即便携性。这就是为什么我的标题本身有POSIX

        基本上,所有投票的答案都是正确的,除了Bash-specific 太多。

        基本上,我只想添加更多关于可移植性的信息。


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

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

          重要提示:我不再推荐这个,因为它正在慢慢被弃用,并且更难组合多个语句。

        2. 想象一下truefalse 这两个词对shell 意味着什么,自己测试一下:

          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. 这是什么意思?嗯,有几件事。

          • 你应该习惯布尔关键字实际上被视为数字,即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
          

        【讨论】:

          【解决方案12】:

          关于语法,这是我用来(通过示例)一致且合理地管理布尔逻辑的简单方法:

          # 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 字符串的长度不为零,则为真。

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

          【讨论】:

            【解决方案13】:

            Bill Parker is getting voted down,因为他的定义与正常的代码约定相反。通常,true 定义为 0,false 定义为非零。 1 适用于 false,9999 和 -1 也适用。与函数返回值相同 - 0 表示成功,任何非零值表示失败。抱歉,我还没有街头信誉可以投票或直接回复他。

            Bash 建议现在习惯使用双括号而不是单括号,Mike Holt 提供的链接解释了它们工作方式的差异。 7.3. Other Comparison Operators

            一方面,-eq 是一个数字运算符,所以有代码

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

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

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

            条件的其他排列也会给出错误的输出。基本上,任何(除了上面列出的错误条件)将变量设置为数值并将其与真/假内置函数进行比较,或将变量设置为真/假内置函数并将其与数值进行比较。此外,任何将变量设置为真/假内置函数并使用-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
            

            你有它。

            【讨论】:

            • 这里没有使用 true/false 内置函数(忽略某些编辑器的语法突出显示可能暗示的内容),尤其是在 […] 情况下,您可以将其视为这里是一个简单的字符串(作为[ 命令的参数给出的字符串)。
            • 你现在拥有它。
            【解决方案14】:

            我收到(我自己的)白痴:

            # setting ----------------
            commonMode=false
            if [[ $something == 'COMMON' ]]; then
                commonMode=true
            fi
            
            # using ----------------
            if $commonMode; then
                echo 'YES, Common Mode'
            else
                echo 'NO, no Common Mode'
            fi
            
            $commonMode && echo 'commonMode is ON  ++++++'
            $commonMode || echo 'commonMode is OFF xxxxxx'
            

            【讨论】:

              【解决方案15】:

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

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

              【讨论】:

                【解决方案16】:

                这是一个短手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"
                

                【讨论】:

                • 是的,功能分解被低估了。
                【解决方案17】:

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

                就我个人而言,我只是想要一些看起来和工作起来都像 C 的东西。

                这个 sn-p 在生产中每天工作多次:

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

                为了让每个人都开心,我进行了测试:

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

                这也很好用。

                $snapshotEvents 计算变量值的内容。所以你需要$

                你并不真的需要括号,我只是觉得它们很有帮助。

                【讨论】:

                • 去掉括号的地方,这正是@miku 在顶部的原始答案。
                • 不带括号的表达式不计算。
                • @will 是的。你不需要 ()s。
                • @Blauhirn ...嗨,我的 cmets 基于在 Linux Mint /Ubuntu PC 上使用 GNU Bash 进行的实验。 theory 你可能是对的,不需要()-s。我唯一的回应是尝试一下,它似乎 依赖 Bash 版本、实际表达式或上下文等。
                【解决方案18】:

                这是对 miku 的 original answer 的改进,解决了 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 建议的那样。

                【讨论】:

                  【解决方案19】:

                  这是一个关于在 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
                  

                  【讨论】:

                    【解决方案20】:

                    您可以使用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 的响应,shFlags 是 GFlags 到 shell 的一个端口。
                    【解决方案21】:

                    另一种使用布尔值的方法是测试值的空性。这样做的好处是可以进行更短的测试:

                    first=1  # A true value
                    second=   # A false value
                    
                    [ -n "$first" ]  && echo 'First var is true'
                    [ -z "$first" ]  && echo 'First var is false'
                    [ -n "$second" ] && echo 'Second var is true'
                    [ -z "$second" ] && echo 'Second var is false'
                    

                    输出:

                    First var is true
                    Second var is false
                    

                    这里是另一种使用 bash 的测试语法:[[ -n $one ]]

                    【讨论】:

                      【解决方案22】:

                      替代方案 - 使用函数

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

                      定义函数不太直观,但检查它的返回值很容易。

                      【讨论】:

                      • 这不是一个可以测试的变量,而是一个常量函数
                      • @jarno 为了脚本的目的,测试函数的返回值与测试变量不同吗?
                      • 嗯,问题是关于变量的。
                      • 是的,虽然在 shell 脚本中的用法是一样的。
                      【解决方案23】:

                      Bash 确实将问题与 [[[(($(( 等混淆了。

                      所有人都在践踏彼此的代码空间。我想这主要是历史性的,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
                        

                        这不是那么漂亮。

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

                      【讨论】:

                      • 你应该以只读方式声明你的常量。使用变量时,请始终使用大括号。这是每个人都应该遵守恕我直言的惯例。此解决方案的一大缺点是您不能将代数表达式与测试标志或字符串比较混合。
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-12-16
                      • 1970-01-01
                      • 2020-08-06
                      • 2017-03-26
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多