了解 Bash 短路
Understanding Bash short-circuiting
首先我不是 Bash 专业人士。几个月前我发现,如果我同时使用 &&
和 ||
短路运算符和花括号,那么如果第一个语句以真实值退出,如果最后一个语句为真块退出非零,那么失败块也将被执行。像这样:
returnNumber 0 && {
echo 'OK'
returnNumber 1
} || {
echo 'NG'
}
将输出:
OK
NG
所以,我为此寻找了最简单的解决方案,并想出了这个:
returnNumber 0 && {
echo 'OK'
returnNumber 1
:
} || {
echo 'NG'
}
我知道,省略内置的冒号很容易,但这是解决方法的正确方法吗?
这个其实很常见Bash pitfall。 不是错误。
returnNumber 0
的计算结果为真,因此第二个块(由逻辑和 &&
连接)也被计算以确保 first && second
的结果仍然为真。
第二个块输出 OK
但计算结果为 false,因此现在 first && second
的结果为 false。这意味着第三部分(由逻辑或 ||
连接)也必须计算,导致 NG
也被显示。
与其依赖 &&
和 ||
,您应该使用 if
语句:
if returnNumber 0; then
echo 'OK'
returnNumber 1
else
echo 'NG'
fi
tl;dr: 当 y
可以 return 非零退出状态时,切勿使用 x && y || z
。
先生Llama 已经正确回答了这个问题,这只是为了快速参考不同 "combinations" 会发生什么。 cmd0
是具有零退出状态的 "command" 而 cmd1
具有非零退出状态。
cmd0() { echo -n "[$@-0]"; return 0; }
cmd1() { echo -n "[$@-1]"; return 1; }
second() { echo "[second]"; }
doit() { echo "case: $@"; eval "$@"; echo; }
doit 'cmd0 start && cmd0 first && second'
doit 'cmd0 start && cmd0 first || second'
doit 'cmd0 start || cmd0 first && second'
doit 'cmd0 start || cmd0 first || second'
doit 'cmd0 start && cmd1 first && second'
doit 'cmd0 start && cmd1 first || second'
doit 'cmd0 start || cmd1 first && second'
doit 'cmd0 start || cmd1 first || second'
doit 'cmd1 start && cmd0 first && second'
doit 'cmd1 start && cmd0 first || second'
doit 'cmd1 start || cmd0 first && second'
doit 'cmd1 start || cmd0 first || second'
doit 'cmd1 start && cmd1 first && second'
doit 'cmd1 start && cmd1 first || second'
doit 'cmd1 start || cmd1 first && second'
doit 'cmd1 start || cmd1 first || second'
产生:
case: cmd0 start && cmd0 first && second
[start-0][first-0][second]
case: cmd0 start && cmd0 first || second
[start-0][first-0]
case: cmd0 start || cmd0 first && second
[start-0][second]
case: cmd0 start || cmd0 first || second
[start-0]
case: cmd0 start && cmd1 first && second
[start-0][first-1]
case: cmd0 start && cmd1 first || second
[start-0][first-1][second]
case: cmd0 start || cmd1 first && second
[start-0][second]
case: cmd0 start || cmd1 first || second
[start-0]
case: cmd1 start && cmd0 first && second
[start-1]
case: cmd1 start && cmd0 first || second
[start-1][second]
case: cmd1 start || cmd0 first && second
[start-1][first-0][second]
case: cmd1 start || cmd0 first || second
[start-1][first-0]
case: cmd1 start && cmd1 first && second
[start-1]
case: cmd1 start && cmd1 first || second
[start-1][second]
case: cmd1 start || cmd1 first && second
[start-1][first-1]
case: cmd1 start || cmd1 first || second
[start-1][first-1][second]
首先我不是 Bash 专业人士。几个月前我发现,如果我同时使用 &&
和 ||
短路运算符和花括号,那么如果第一个语句以真实值退出,如果最后一个语句为真块退出非零,那么失败块也将被执行。像这样:
returnNumber 0 && {
echo 'OK'
returnNumber 1
} || {
echo 'NG'
}
将输出:
OK
NG
所以,我为此寻找了最简单的解决方案,并想出了这个:
returnNumber 0 && {
echo 'OK'
returnNumber 1
:
} || {
echo 'NG'
}
我知道,省略内置的冒号很容易,但这是解决方法的正确方法吗?
这个其实很常见Bash pitfall。 不是错误。
returnNumber 0
的计算结果为真,因此第二个块(由逻辑和 &&
连接)也被计算以确保 first && second
的结果仍然为真。
第二个块输出 OK
但计算结果为 false,因此现在 first && second
的结果为 false。这意味着第三部分(由逻辑或 ||
连接)也必须计算,导致 NG
也被显示。
与其依赖 &&
和 ||
,您应该使用 if
语句:
if returnNumber 0; then
echo 'OK'
returnNumber 1
else
echo 'NG'
fi
tl;dr: 当 y
可以 return 非零退出状态时,切勿使用 x && y || z
。
先生Llama 已经正确回答了这个问题,这只是为了快速参考不同 "combinations" 会发生什么。 cmd0
是具有零退出状态的 "command" 而 cmd1
具有非零退出状态。
cmd0() { echo -n "[$@-0]"; return 0; }
cmd1() { echo -n "[$@-1]"; return 1; }
second() { echo "[second]"; }
doit() { echo "case: $@"; eval "$@"; echo; }
doit 'cmd0 start && cmd0 first && second'
doit 'cmd0 start && cmd0 first || second'
doit 'cmd0 start || cmd0 first && second'
doit 'cmd0 start || cmd0 first || second'
doit 'cmd0 start && cmd1 first && second'
doit 'cmd0 start && cmd1 first || second'
doit 'cmd0 start || cmd1 first && second'
doit 'cmd0 start || cmd1 first || second'
doit 'cmd1 start && cmd0 first && second'
doit 'cmd1 start && cmd0 first || second'
doit 'cmd1 start || cmd0 first && second'
doit 'cmd1 start || cmd0 first || second'
doit 'cmd1 start && cmd1 first && second'
doit 'cmd1 start && cmd1 first || second'
doit 'cmd1 start || cmd1 first && second'
doit 'cmd1 start || cmd1 first || second'
产生:
case: cmd0 start && cmd0 first && second
[start-0][first-0][second]
case: cmd0 start && cmd0 first || second
[start-0][first-0]
case: cmd0 start || cmd0 first && second
[start-0][second]
case: cmd0 start || cmd0 first || second
[start-0]
case: cmd0 start && cmd1 first && second
[start-0][first-1]
case: cmd0 start && cmd1 first || second
[start-0][first-1][second]
case: cmd0 start || cmd1 first && second
[start-0][second]
case: cmd0 start || cmd1 first || second
[start-0]
case: cmd1 start && cmd0 first && second
[start-1]
case: cmd1 start && cmd0 first || second
[start-1][second]
case: cmd1 start || cmd0 first && second
[start-1][first-0][second]
case: cmd1 start || cmd0 first || second
[start-1][first-0]
case: cmd1 start && cmd1 first && second
[start-1]
case: cmd1 start && cmd1 first || second
[start-1][second]
case: cmd1 start || cmd1 first && second
[start-1][first-1]
case: cmd1 start || cmd1 first || second
[start-1][first-1][second]