Bash 中的 If else 条件

Bash 中的 If else 条件

我正在尝试创建一个if else使用 3 个布尔变量的 bash 脚本:

  1. CHECK_X
  2. CHECK_Y
  3. CHECK_Z

如果CHECK_X或者CHECK_Y错误的并且CHECK_Z也是,错误的然后我通知用户条件不满足。所以我创建了以下内容:

if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
  echo "Condition not met"
fi

使用上面的代码,如果 或CHECK_XCHECK_Y正确的,尽管CHECK_Z仍然错误的这种情况持续下去,这不是我想要的。

我需要其中一个CHECK_X并且CHECK_Z成为真的CHECK_Y并且CHECK_Z成为真的在我的条件满足之前。

使用以下代码也不起作用:

if [[ "$CHECK_X" && "$CHECK_Z" == "FALSE" ]] || [[ "$CHECK_Y" && "$DCHECK_Z" == "FALSE" ]]; then
  echo "Condition not met"
fi    

我认为我在某个地方把自己搞得太复杂了,希望得到一些专家的建议。谢谢

更新:

根据最近的一些反馈,我将代码更新为:

if [[ "$CHECK_X" == "FALSE" || "$CHECK_Y" == "FALSE" ]] && [[ "$CHECK_Z" == "FALSE" ]]; then
  echo "Condition not met"
fi

然而经过测试我有以下...

如果:

  1. CHECK_X="TRUE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="TRUE"

输出:Condition not met。这是不正确因为条件13TRUE

如果:

  1. CHECK_X="TRUE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="FALSE"

输出:Condition not met。这是正确的因为条件13都是不是 TRUE

如果:

  1. CHECK_X="FALSE"
  2. CHECK_Y="TRUE"
  3. CHECK_Z="FALSE"

输出:脚本完成。这是不正确因为条件23不是 TRUE

如果:

  1. CHECK_X="FALSE"
  2. CHECK_Y="TRUE"
  3. CHECK_Z="TRUE"

输出:脚本完成。这是正确的因为条件23TRUE

如果:

  1. CHECK_X="FALSE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="FALSE"

输出:Condition not met。这是正确的因为条件13或者23不是 TRUE

答案1

您需要检查每个变量:

if [[ "$CHECKX" == "FALSE" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
  echo "Condition not met"
fi

当你有 时if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]],这只是检查是否$CHECKX已设置,它仅$CHECKY与字符串进行比较FALSE。为了显示:

$ CHECKX=foo
$ CHECKY=TRUE
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true
$ CHECKX=""
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
$ 

正如您在上面看到的,仅当设置为空字符串时检查才会失败,CHECKX因此测试[[ "$CHECKX" ]]评估为 false。如果它设置为任何值,包括0,那么它就会失败:

$ CHECKX=0
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true

答案2

其他人已经解决了用于存储和测试布尔值和变量的编码技术,因此我将只关注代码的逻辑。

当您正在研究多变量布尔函数时,构建一个真值表这样您就清楚函数的正确输出应该是什么。请检查我是否正确理解了您的帖子,但我相信对于函数,Q(X,Y,Z)的值Q取决于XY如下Z所示:

“如果 X 或 Y 为假且 Z 也为假,那么……条件不满足。”

因为你已经否定了这一点,所以我将假设在所有其他情况下,条件遇见了。

X Z
错误的 错误的 错误的 错误的
错误的 错误的 真的 真的
错误的 真的 错误的 错误的
错误的 真的 真的 真的
真的 错误的 错误的 错误的
真的 错误的 真的 真的
真的 真的 错误的 真的
真的 真的 真的 真的

布尔代数中的一个常见公理是,我们可以构建两个子函数 Q1 和 Q2 来解决表的互斥部分,而不是构建一个函数 Q 来解决所有情况。然后我们可以对ORQ1和Q2的结果进行简单处理,得到最终的解Q。

例如,令 Q1 为X表上半部分中为 FALSE 的解。请注意,在这四种情况下,ZQ列是相同的。该Y列是无关的,因此我们可以说当X为 FALSE 时,函数结果与 直接相关Z

for X=FALSE, Q1 = !X && Z
X Z Q1
错误的 错误的 错误的 错误的
错误的 错误的 真的 真的
错误的 真的 错误的 错误的
错误的 真的 真的 真的

在表的下半部分,其中X为 TRUE,函数结果 Q2 直接与 相关Y || Z

for X=TRUE, Q2 = X && (Y || Z)
X Z Q2
真的 错误的 错误的 错误的
真的 错误的 真的 真的
真的 真的 错误的 真的
真的 真的 真的 真的

由于 Q1 和 Q2 是在完全独立的域上定义的,因此我们可以说结果 Q 将恰好是其中之一。那是,

Q = Q1 || Q2
X Z Q1 Q2 Q1 || Q2
错误的 错误的 错误的 错误的 错误的
错误的 错误的 真的 真的 真的
错误的 真的 错误的 错误的 错误的
错误的 真的 真的 真的 真的
真的 错误的 错误的 错误的 错误的
真的 错误的 真的 真的 真的
真的 真的 错误的 真的 真的
真的 真的 真的 真的 真的

现在我们需要将这两种情况组合成一个布尔公式。简单地连接所有内容很诱人,但对于正确的布尔公式,我们必须考虑计算的顺序。与普通代数类似,乘法在加法之前执行,布尔代数规定交集 (AND) 在并集 (OR) 之前执行。因此,我们将在子表达式两边加上括号。

两者皆为X假,我们的结果是Z

if !X then Q1 = Z

或者X是真的,我们的结果是Y || Z

if  X then Q2 = Y || Z

我们的答案实际上是一个或另一个:

Q = (!X && Q1) || (X && Q2)

联合的短路评估和换向将使我们能够将其重新表述为:

Q = (X && Q2) || (Q1)

代入 Q1 和 Q2:

Q = (X && (Y || Z)) || (Z)

仅在需要的地方使用括号:

Q = X && (Y || Z) || Z

也可以写成:

Q = Z || X && (Y || Z) 

当 Z 为真时,OR 的右侧无关紧要。当 Z 为假时,OR 的右侧变为:

X && (Y || FALSE)

要不就:

X && Y

所以我们最终的函数 Q 是:

Q = Z || X && Y

我们可以根据真值表来验证这一点,因为在每种情况下,当 Z 为真时,Q 也为真。在 Z 为假的四种情况下,只有当 X 和 Y 都为真时,Q 才为真。

X Z X && Y
错误的 错误的 错误的 错误的 错误的
错误的 错误的 真的 错误的 真的
错误的 真的 错误的 错误的 错误的
错误的 真的 真的 错误的 真的
真的 错误的 错误的 错误的 错误的
真的 错误的 真的 错误的 真的
真的 真的 错误的 真的 真的
真的 真的 真的 真的 真的

答案3

用[多个]双重否定表达您的要求(“如果 CHECK_X 或 CHECK_Y 是错误的CHECK_Z 也是,错误的然后我通知用户条件是不是遇见。”)使得理解和实施它们比以积极的方式表达它们要困难得多。

避免在您的需求或代码中使用诸如!ornot或比较之类的否定词,并避免在变量名称中使用任何否定术语,因为同样的原因 - 肯定总是比否定更容易理解,如果您没有否定,那么您不能以极其难以理解的双重否定结束。falsenot

这就是你所说的你的要求是:

如果 CHECK_X 或 CHECK_Y 为假且 CHECK_Z 也为假,则我通知用户条件不满足。

我们可以直接将您的需求转换为伪代码:

if ( ((CHECK_X == false) || (CHECK_Y == false)) && (CHECK_Z == false) ); then
    print 'conditions are not met'
else
    conditions are met so do nothing
fi

现在,为了减少负面影响,如果我们首先将if“满足条件”(即正面而不是负面)作为正在测试的条件,那么它就会变成:

if ! ( ((CHECK_X == false) || (CHECK_Y == false)) && (CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

所以现在我们有一个if测试,可以让我们得到积极的“满足条件”而不是消极的“条件满足”不是现在我们只需要通过分解出领先的“非”运算符,并将与 的比较更改为与 的比较,使if测试本身变得积极而不是消极。!falsetrue

如果我们应用布尔代数将负数移到!最外面的括号内,则条件变为:

if ( !((CHECK_X == false) || (CHECK_Y == false)) || !(CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

如果我们再次应用相同的方法将第一个移动到!它适用的条件内,我们会得到:

if ( ( !(CHECK_X == false) && !(CHECK_Y == false) ) || !(CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

我们可以通过将每个更改为!...false来简化true

if ( ((CHECK_X == true) && (CHECK_Y == true)) || (CHECK_Z == true) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

现在我们有一个完全积极的if测试,产生积极的结果“满足条件”,因此突然变得非常清楚,您的要求很简单,如果 CHECK_Z 或 CHECK_X 和 CHECK_Y 都为真,则满足条件,否则满足条件t,因此我们可以使用if-else上面的或更简洁的方法轻松实现该要求:

$ cat tst.sh
#!/usr/bin/env bash

testit() {
    [[ (("$CHECK_X" == "TRUE") && ("$CHECK_Y" == "TRUE")) || ("$CHECK_Z" == "TRUE") ]] ||
        printf 'conditions are not met\n'
}

for CHECK_X in TRUE FALSE; do
    for CHECK_Y in TRUE FALSE; do
        for CHECK_Z in TRUE FALSE; do
            printf 'CHECK_X=%s, CHECK_Y=%s, CHECK_Z=%s %s\n' \
                    "$CHECK_X" "$CHECK_Y" "$CHECK_Z" "$(testit)"
        done
    done
done

$ ./tst.sh
CHECK_X=TRUE, CHECK_Y=TRUE, CHECK_Z=TRUE
CHECK_X=TRUE, CHECK_Y=TRUE, CHECK_Z=FALSE
CHECK_X=TRUE, CHECK_Y=FALSE, CHECK_Z=TRUE
CHECK_X=TRUE, CHECK_Y=FALSE, CHECK_Z=FALSE conditions are not met
CHECK_X=FALSE, CHECK_Y=TRUE, CHECK_Z=TRUE
CHECK_X=FALSE, CHECK_Y=TRUE, CHECK_Z=FALSE conditions are not met
CHECK_X=FALSE, CHECK_Y=FALSE, CHECK_Z=TRUE
CHECK_X=FALSE, CHECK_Y=FALSE, CHECK_Z=FALSE conditions are not met

答案4

如果您想要 BASH 中的布尔值,那么最接近真实布尔值的是使用
数和壳算术。

因为: CHECK_X="true"; [[ $CHECK_X == "true" ]];
是一个字符串比较,其中正确的参数是一个 glob 模式(如果不加引号),然后生成类似布尔值、退出代码 0 或 1 的内容

尝试 shell 算术:

set +o histexpand # only needed in an interactive shell

declare -i CHECK_X=0 CHECK_Y=0 CHECK_Z=0   #-- Boolean 0 or 1 , false or true

# now you can use boolean syntax inside shell arithmetic ((...))
if (( (!CHECK_X || !CHECK_Y) && !CHECK_Z )); then echo "yep"; fi
if (( CHECK_X || CHECK_Y || !CHECK_Z )); then echo "pep"; fi

declare test="hello"  # with string
if (( CHECK_X && CHECK_Y && CHECK_Z && test=="hello" )); then echo ".."; fi

相关内容