首页 文章

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

提问于
浏览
708

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]

16 回答

  • 871

    为什么不使用比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
    
  • 14

    在许多编程语言中,布尔类型是整数的子类型,或者实现为整数的子类型,其中 true 的行为类似于 1 ,而 false 的行为类似于 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”完全相同 .

  • 640

    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
    
    • 你必须受到纪律处分 . 您的 testvar 必须始终设置为 $TRUE$FALSE .

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

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

    • 缺点是偶尔使用 $

    testvar=$TRUE
    

    这不是那么漂亮 .

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

  • 40

    这是一个简短的 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
    }
    

    Example 1

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

    Example 2

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

    使用算术表达式 .

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

    输出:

    真的不是假的

  • 11

    长话短说:

    bash中没有布尔值

    bash所拥有的是比较和条件方面的布尔表达式 . 也就是说,你可以在bash中声明和比较的是字符串和数字 . 而已 .

    无论你在bash中看到 truefalse ,它都是一个字符串或一个命令/ builtin,它只用于退出代码 .

    这个语法......

    if true; then ...
    

    基本上......

    if COMMAND; then ...
    

    只要命令返回退出代码0,条件就为真 .

    你也可以这样做:

    if which foo; then echo "program foo found"; fi
    

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

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

    只是...的语法糖

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

    因此,当在上述任何构造中使用 truefalse 时,实际上只是将字符串 "true""false" 传递给测试命令 . 这是一个例子:

    信不信由你,但这些条件都产生了 same result

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

    TL; DR;总是与字符串或数字进行比较

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

    DO

    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. Can be used for strict checking of dangerous operations. This condition is false for anything but the literal string "true".
    
  • 2

    Revised Answer (Feb 12, 2014)

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

    Original Answer

    注意事项: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日修订前的评论仅涉及原始答案,并且许多评论与修订后的答案相关时是错误的 . 例如,Dennis Williamson关于2010年6月2日bash builtin true 的评论仅适用于原始答案,而非修订版 .

  • 0

    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
    

    条件的其他排列也会产生错误的输出 . 基本上,将变量设置为数值并将其与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
    

    你有它 .

  • 1

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

    我想念这里的关键点,即便携性 . 这就是为什么我的 Headers 本身就是POSIX .

    基本上,所有投票的答案都是正确的,除了它们是特定的_s7615_特定的太多 .

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


    169 [] 中的 ] 括号不是必需的,您可以省略它们并直接使用 test 命令:

    test "$var" = true && CodeIfTrue || CodeIfFalse
    
    • 想象一下 truefalse 对shell的意思是什么,自己测试一下:
    echo $((true))
    

    0

    echo $((false))
    

    1

    但是使用引号:

    echo $(("true"))
    

    bash:“true”:语法错误:操作数预期(错误标记为“”true“”)
    sh(破折号):sh:1:算术表达式:期待主要:“”真“”

    同样适用于:

    echo $(("false"))
    

    shell不能解释它而不是字符串 . 我希望你能够了解使用正确的关键字 without 引用有多好 .

    但在之前的答案中没有人说过 .

    • 这意味着什么?好吧,好几件事 .

    • 你应该习惯布尔关键字实际上被视为数字,即 true = 0false = 1 ,记住所有非零值都被视为 false .

    • 因为它们被视为数字,你应该像对待它们一样,即如果你定义变量说:

    var_a=true
    echo "$var_a"
    

    是的

    你可以创建一个相反的值:

    var_a=$((1 - $var_a))
    echo "$var_a"
    

    1

    正如您自己可以看到的,shell在您第一次使用它时会打印 true 字符串,但从那时起,它们分别通过数字 01 工作 .


    最后,您应该对所有这些信息做些什么

    • 第一个好习惯是分配 0 而不是 true ; 1 而不是 false .

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

    test "$var" -eq 0 && CodeIfTrue || CodeIfFalse
    
  • 6

    TL; DR

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

    Miku(原创)答案的问题

    我做 not 推荐接受的答案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
    

    通常,只有当您的"boolean"变量(在此示例中为 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 . 在上述情况下,您应该收到一条警告,指出找不到该命令 . 但我们仍然可以做得更好(请参阅我在底部的建议) .

    另请参阅Mike Holt对Miku原始答案的解释 .

    Hbar答案的问题

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

    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,但是你的代码将更具防御性 .


    脚注

    • Miku's答案已被编辑,不再包含(已知)缺陷 .

    • 不是详尽的清单 .

    • 此上下文中的有效命令表示存在的命令 . 如果正确或错误地使用命令并不重要 . 例如 . 即使没有这样的手册页, man woman 仍将被视为有效命令 .

    • 对于无效(不存在)命令,Bash只会抱怨找不到该命令 .

    • 如果你关心长度,第一个建议是最短的 .

  • 13

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

    与许多其他编程语言不同,Bash不会通过"type." [1]隔离其变量

    所以答案很清楚 . bash中没有 boolean variable . 但是:

    使用declare语句,我们可以将值赋值限制为变量 . [2]

    #!/bin/bash
    declare -ir BOOL=(0 1) #remember BOOL can't be unset till this shell terminate
    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 选项用于明确声明变量为 readonly . 希望目的很明确 .

  • 0

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

    miku's answer中的代码与Bash内置 true 完全无关,也与 /bin/true 完全无关,也与 true 命令的任何其他风格无关 . 在这种情况下, true 只不过是一个简单的字符串,并且不会通过变量赋值或条件表达式的求值来调用 true command / builtin .

    以下代码在功能上与miku的答案中的代码相同:

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

    这里的 only 差异在于被比较的四个字符是'y','e','a'和'h'而不是't',_ 'r','u'和'e' . 's it. There'没有尝试调用名为 yeah 的命令或内置,也没有(在miku的例子中)当Bash解析令牌 true 时进行任何类型的特殊处理 . 它只是一个字符串,而且是一个完全随意的字符串 .

    Update (2014-02-19): 跟随miku 's answer, now I see where some of the confusion is coming from. Miku'中的链接后,答案使用单括号,但他链接到的代码段不使用括号 . 只是:

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

    两个代码片段的行为方式都相同,但括号完全改变了引擎盖下的内容 .

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

    No brackets:

    • 将变量 $the_world_is_flat 展开为字符串 "true" .

    • 尝试将字符串 "true" 解析为命令 .

    • 查找并运行 true 命令(内置或 /bin/true ,具体取决于Bash版本) .

    • true 命令的退出代码(始终为0)与0进行比较 . 回想一下,在大多数shell中,退出代码0表示成功,其他任何表示失败 .

    • 由于退出代码为0(成功),执行 if 语句的 then 子句

    Brackets:

    • 将变量 $the_world_is_flat 展开为字符串 "true" .

    • 解析现在完全展开的条件表达式,其形式为 string1 = string2 . = 运算符是bash的字符串比较运算符 . 所以...

    • "true""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
    

    Update (2014-04-14) 要回答有关 === :AFAIK之间差异的评论中的问题,没有区别 . == 运算符是 = 的特定于Bash的同义词,据我所见,它们在所有上下文中的工作方式完全相同 .

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

    例如,你显然无法使用 == 进行变量赋值,例如 var=="foo" (技术上你可以做到这一点,但 var 的值将是 "=foo" ,因为Bash在这里没有看到 == 运算符,它看到 = (赋值运算符,后跟文字值 ="foo" ,它只是 "=foo" ) .

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

  • 1

    很久以前,当我们所有的都是 sh 时,通过依赖 test 程序的约定来处理布尔值,其中 test 如果没有参数运行则返回错误的退出状态 . 这允许人们将未设置的变量视为false,将变量设置为任何值为true . 今天,测试内置于 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 但具有更好语法的复合命令 [[ :不需要引用带空格的变量,可以使用 &&|| 作为具有奇怪优先级的逻辑运算符,并且没有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时 .

  • 120

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

    就个人而言,我只想拥有像C一样的外观和作品 .

    这个片段每天在制作中多次使用:

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

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

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

    哪个也很好 .

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

    你真的不需要括号,我发现它们很有帮助 .

  • 3

    这是一个适合我的简单示例:

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

    这是对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建议的那样 .

相关问题