bash - if取反 - shell判断true




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

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

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

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

使用声明语句,我们可以将赋值赋给变量。 [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"

declarereadonlyr选项用于明确声明变量是只读的 。 希望目的很明确。

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

variable=$false

variable=$true

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

if [ $variable ]

if [ !$variable ]

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

我想念这里的关键点,这是可移植性。 这就是为什么我的头本身有POSIX

从本质上讲,所有投票答案都是正确的,除了他们特别是BASH以外。

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

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

    test "$var" = true && CodeIfTrue || CodeIfFalse
    
  2. 想象一下这些词的truefalse对壳体意味着什么,请亲自测试一下:

    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

    • 由于它们被视为数字,所以你也应该这样对待它们,即如果你定义了变量say:

      var_a=true
      echo "$var_a"
      
       true
      

      您可以通过以下方式创建相反的值:

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

      正如你自己看到的,shell在你第一次使用它的时候会打印出true字符串,但是从那以后,它们分别通过数字0或者1工作。

最后,你应该怎么处理所有这些信息

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

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

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

BASH真的把这个问题弄糊涂了, [[(($((等)

所有对待彼此的代码空间。 我想这主要是历史性的, bash偶尔会假装偶尔。

大多数时候,我可以选择一种方法并坚持下去。 在这个例子中,我倾向于声明(最好在我可以包含在我的实际脚本中的通用库文件中)。

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
    

    这不太漂亮。

这不是一个完美的解决方案,但它涵盖了每一个案例,我需要这样一个测试。


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"

为什么不使用比真实和错误更好的值呢?而不是伪造布尔值并为未来的读者留下陷阱。

例如:

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

使用算术表达式。

#!/bin/bash

false=0
true=1

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

输出:

真正
不是假的


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

就我个人而言,我只想拥有像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


比尔帕克被拒绝了,因为他的定义与正常的代码惯例相反。 通常情况下,true被定义为0,false被定义为非零。 1将会失败,9999和-1也是如此。 与函数返回值相同 - 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]] =成功,但也会评估为[[0 -eq false]] =成功,这是错误的(嗯......那个内建值是一个数值?)。

#**** 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

所以,现在到了什么工作。 使用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

你有它。


这是米库最初的答案的一个改进,它解决了丹尼斯威廉姆森关于这个案例的关注,其中没有设置变量:

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

关于变量中令人讨厌的内容的其他情况,这是任何外部输入馈给程序的问题。

任何外部输入必须在信任之前进行验证。 但是,只有在接收到输入信息时才需要进行一次验证。

它不需要像丹尼斯威廉姆森所说的那样使用变量来影响程序的性能。


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

miku的回答中的代码与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

这里唯一的区别是,比较的四个字符是'y','e','a'和'h',而不是't','r','u'和'e'。 而已。 没有任何尝试调用命令或内置命名为yeah ,也没有(在miku的例子中)当bash分析令牌为true时进行的任何特殊处理。 这只是一个字符串,而且完全是任意的。

更新(2/19/2014):在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. 是的,这两个字符串是相同的,所以条件的值是真的。
  5. 执行if语句的then子句。

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

为了将这一点引入家庭,请考虑以下两段代码:

此代码(如果以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日)要回答评论中关于=== AFAIK之间差异的问题,没有区别。 ==运算符是=的bash特定的同义词,就我所见,它们在所有上下文中都完全相同。 但是,请注意,我正在专门讨论在[ ][[ ]]测试中使用的===字符串比较运算符。 我并不是建议===在bash中随处可以互换。 例如,你显然不能用==做变量赋值,比如var=="foo" (技术上你可以这样做,但是var的值将是"=foo" ,因为bash没有看到==运算符在这里,它看到一个= (赋值)运算符,后面是字面值="foo" ,它变成了"=foo" )。

此外,尽管===可以互换,但您应该记住,这些测试的工作方式取决于您在[ ]还是[[ ]]使用它,以及操作数是否被引用。 你可以在这里阅读更多关于它的信息: 7.3其他比较运算符 (向下滚动到讨论=== )。





sh