我正在尝试创建一个if else
使用 3 个布尔变量的 bash 脚本:
CHECK_X
CHECK_Y
CHECK_Z
如果CHECK_X
或者CHECK_Y
是错误的并且CHECK_Z
也是,错误的然后我通知用户条件不满足。所以我创建了以下内容:
if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
echo "Condition not met"
fi
使用上面的代码,如果 或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
我认为我在某个地方把自己搞得太复杂了,希望得到一些专家的建议。谢谢
更新:
根据最近的一些反馈,我将代码更新为:
if [[ "$CHECK_X" == "FALSE" || "$CHECK_Y" == "FALSE" ]] && [[ "$CHECK_Z" == "FALSE" ]]; then
echo "Condition not met"
fi
然而经过测试我有以下...
如果:
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
。
答案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
取决于X
,Y
如下Z
所示:
“如果 X 或 Y 为假且 Z 也为假,那么……条件不满足。”
因为你已经否定了这一点,所以我将假设在所有其他情况下,条件是遇见了。
X | 是 | Z | 问 |
---|---|---|---|
错误的 | 错误的 | 错误的 | 错误的 |
错误的 | 错误的 | 真的 | 真的 |
错误的 | 真的 | 错误的 | 错误的 |
错误的 | 真的 | 真的 | 真的 |
真的 | 错误的 | 错误的 | 错误的 |
真的 | 错误的 | 真的 | 真的 |
真的 | 真的 | 错误的 | 真的 |
真的 | 真的 | 真的 | 真的 |
布尔代数中的一个常见公理是,我们可以构建两个子函数 Q1 和 Q2 来解决表的互斥部分,而不是构建一个函数 Q 来解决所有情况。然后我们可以对OR
Q1和Q2的结果进行简单处理,得到最终的解Q。
例如,令 Q1 为X
表上半部分中为 FALSE 的解。请注意,在这四种情况下,Z
和Q
列是相同的。该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
或比较之类的否定词,并避免在变量名称中使用任何否定术语,因为同样的原因 - 肯定总是比否定更容易理解,如果您没有否定,那么您不能以极其难以理解的双重否定结束。false
not
这就是你所说的你的要求是:
如果 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
测试本身变得积极而不是消极。!
false
true
如果我们应用布尔代数将负数移到!
最外面的括号内,则条件变为:
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