我正在尝试创建一个if else使用 3 个布尔变量的 bash 脚本:
CHECK_XCHECK_YCHECK_Z如果CHECK_XorCHECK_Y为假并且CHECK_Z也是假,那么我通知用户条件不满足。所以我创建了以下内容:
if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
echo "Condition not met"
fi
Run Code Online (Sandbox Code Playgroud)
使用上面的代码,如果 或CHECK_X是CHECK_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
Run Code Online (Sandbox Code Playgroud)
我认为我在某个地方把自己搞得太复杂了,希望得到一些专家的建议。谢谢
更新:
根据最近的一些反馈,我将代码更新为:
if [[ "$CHECK_X" == "FALSE" || "$CHECK_Y" == "FALSE" ]] && [[ "$CHECK_Z" == "FALSE" ]]; then
echo "Condition not met"
fi
Run Code Online (Sandbox Code Playgroud)
然而经过测试我有以下...
如果:
CHECK_X="TRUE"CHECK_Y="FALSE"CHECK_Z="TRUE"输出:Condition not met。这是不正确的,因为条件1和3是TRUE。
如果:
CHECK_X="TRUE"CHECK_Y="FALSE"CHECK_Z="FALSE"输出:Condition not met。这是正确的,因为条件1和3都不成立 TRUE。
如果:
CHECK_X="FALSE"CHECK_Y="TRUE"CHECK_Z="FALSE"输出:脚本完成。这是不正确的,因为条件2和3不成立 TRUE。
如果:
CHECK_X="FALSE"CHECK_Y="TRUE"CHECK_Z="TRUE"输出:脚本完成。这是正确的,因为条件2和3是TRUE。
如果:
CHECK_X="FALSE"CHECK_Y="FALSE"CHECK_Z="FALSE"输出:Condition not met。这是正确的,因为条件1和3或2和3不成立 TRUE。
您需要检查每个变量:
if [[ "$CHECKX" == "FALSE" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
echo "Condition not met"
fi
Run Code Online (Sandbox Code Playgroud)
当你有 时if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]],这只是检查是否$CHECKX已设置,它仅$CHECKY与字符串进行比较FALSE。为了显示:
$ CHECKX=foo
$ CHECKY=TRUE
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true
$ CHECKX=""
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
$
Run Code Online (Sandbox Code Playgroud)
正如您在上面看到的,仅当CHECKX设置为空字符串时检查才会失败,因此测试[[ "$CHECKX" ]]评估为 false。如果它设置为任何值,包括0,那么它就会失败:
$ CHECKX=0
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true
Run Code Online (Sandbox Code Playgroud)
其他人已经解决了用于存储和测试布尔值和变量的编码技术,因此我将只关注代码的逻辑。
当您正在研究多变量布尔函数时,请构建一个真值表,以便您清楚函数的正确输出应该是什么。请检查我是否正确理解了您的帖子,但我相信对于函数,Q(X,Y,Z)的值Q取决于X,Y如下Z所示:
“如果 X 或 Y 为假且 Z 也为假,那么……条件不满足。”
因为您已经否定了这一点,所以我将假设在所有其他情况下都满足该条件。
| X | 是 | Z | 问 |
|---|---|---|---|
| 错误的 | 错误的 | 错误的 | 错误的 |
| 错误的 | 错误的 | 真的 | 真的 |
| 错误的 | 真的 | 错误的 | 错误的 |
| 错误的 | 真的 | 真的 | 真的 |
| 真的 | 错误的 | 错误的 | 错误的 |
| 真的 | 错误的 | 真的 | 真的 |
| 真的 | 真的 | 错误的 | 真的 |
| 真的 | 真的 | 真的 | 真的 |
布尔代数中的一个常见公理是,我们可以构建两个子函数 Q1 和 Q2 来解决表的互斥部分,而不是构建一个函数 Q 来解决所有情况。然后我们可以对ORQ1和Q2的结果进行简单处理,得到最终的解Q。
例如,令 Q1X为表上半部分中为 FALSE 的解。请注意,在这四种情况下,Z和Q列是相同的。该Y列是无关的,因此我们可以说当为XFALSE 时,函数结果与 直接相关Z:
for X=FALSE, Q1 = !X && Z
Run Code Online (Sandbox Code Playgroud)
| X | 是 | Z | Q1 |
|---|---|---|---|
| 错误的 | 错误的 | 错误的 | 错误的 |
| 错误的 | 错误的 | 真的 | 真的 |
| 错误的 | 真的 | 错误的 | 错误的 |
| 错误的 | 真的 | 真的 | 真的 |
在表的下半部分,其中X为 TRUE,函数结果 Q2 直接与 相关Y || Z:
for X=TRUE, Q2 = X && (Y || Z)
Run Code Online (Sandbox Code Playgroud)
| X | 是 | Z | Q2 |
|---|---|---|---|
| 真的 | 错误的 | 错误的 | 错误的 |
| 真的 | 错误的 | 真的 | 真的 |
| 真的 | 真的 | 错误的 | 真的 |
| 真的 | 真的 | 真的 | 真的 |
由于 Q1 和 Q2 是在完全独立的域上定义的,因此我们可以说结果 Q 将恰好是其中之一。那是,
Q = Q1 || Q2
Run Code Online (Sandbox Code Playgroud)
| X | 是 | Z | Q1 | Q2 | Q1 || Q2 |
|---|---|---|---|---|---|
| 错误的 | 错误的 | 错误的 | 错误的 | 错误的 | |
| 错误的 | 错误的 | 真的 | 真的 | 真的 | |
| 错误的 | 真的 | 错误的 | 错误的 | 错误的 | |
| 错误的 | 真的 | 真的 | 真的 | 真的 | |
| 真的 | 错误的 | 错误的 | 错误的 | 错误的 | |
| 真的 | 错误的 | 真的 | 真的 | 真的 | |
| 真的 | 真的 | 错误的 | 真的 | 真的 | |
| 真的 | 真的 | 真的 | 真的 | 真的 |
现在我们需要将这两种情况组合成一个布尔公式。简单地连接所有内容很诱人,但对于正确的布尔公式,我们必须考虑计算的顺序。与普通代数类似,乘法在加法之前执行,布尔代数规定交集 (AND) 在并集 (OR) 之前执行。因此,我们将在子表达式两边加上括号。
两者皆为X假,我们的结果是Z:
if !X then Q1 = Z
Run Code Online (Sandbox Code Playgroud)
或者X是真的,我们的结果是Y || Z:
if X then Q2 = Y || Z
Run Code Online (Sandbox Code Playgroud)
我们的答案实际上是一个或另一个:
Q = (!X && Q1) || (X && Q2)
Run Code Online (Sandbox Code Playgroud)
联合的短路评估和换向将使我们能够将其重新表述为:
Q = (X && Q2) || (Q1)
Run Code Online (Sandbox Code Playgroud)
代入 Q1 和 Q2:
Q = (X && (Y || Z)) || (Z)
Run Code Online (Sandbox Code Playgroud)
仅在需要的地方使用括号:
Q = X && (Y || Z) || Z
Run Code Online (Sandbox Code Playgroud)
也可以写成:
Q = Z || X && (Y || Z)
Run Code Online (Sandbox Code Playgroud)
当 Z 为真时,OR 的右侧无关紧要。当 Z 为假时,OR 的右侧变为:
X && (Y || FALSE)
Run Code Online (Sandbox Code Playgroud)
要不就:
X && Y
Run Code Online (Sandbox Code Playgroud)
所以我们最终的函数 Q 是:
Q = Z || X && Y
Run Code Online (Sandbox Code Playgroud)
我们可以根据真值表来验证这一点,因为在每种情况下,当 Z 为真时,Q 也为真。在 Z 为假的四种情况下,只有当 X 和 Y 都为真时,Q 才为真。
| X | 是 | Z | X && Y | 问 |
|---|---|---|---|---|
| 错误的 | 错误的 | 错误的 | 错误的 | 错误的 |
| 错误的 | 错误的 | 真的 | 错误的 | 真的 |
| 错误的 | 真的 | 错误的 | 错误的 | 错误的 |
| 错误的 | 真的 | 真的 | 错误的 | 真的 |
| 真的 | 错误的 | 错误的 | 错误的 | 错误的 |
| 真的 | 错误的 | 真的 | 错误的 | 真的 |
| 真的 | 真的 | 错误的 | 真的 | 真的 |
| 真的 | 真的 | 真的 | 真的 | 真的 |
用[多个]双重否定表达您的要求(“如果 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
Run Code Online (Sandbox Code Playgroud)
现在,为了减少负面影响,如果我们首先将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
Run Code Online (Sandbox Code Playgroud)
所以现在我们有了一个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
Run Code Online (Sandbox Code Playgroud)
如果我们再次应用相同的方法将第一个移动!到它适用的条件内,我们会得到:
if ( ( !(CHECK_X == false) && !(CHECK_Y == false) ) || !(CHECK_Z == false) ); then
conditions are met so do nothing
else
print 'conditions are not met'
fi
Run Code Online (Sandbox Code Playgroud)
我们可以通过将每个更改!...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
Run Code Online (Sandbox Code Playgroud)
现在我们有一个完全积极的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
Run Code Online (Sandbox Code Playgroud)
$ ./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
Run Code Online (Sandbox Code Playgroud)