快捷方式: (expr1 && expr2)
,而不是if ... fi
声明。如果要通过循环生成 , ,... ,你能做到吗expr1
?expr2
这是一个玩具示例:
$ for cond in {0,0,0}; do if [[ $cond = 0 ]]; then echo 0; else echo 1; break; fi; done && echo "true" || echo "false"
0
0
0
true
$ for cond in {0,1,0}; do if [[ $cond = 0 ]]; then echo 0; else echo 1; break; fi; done && echo "true" || echo "false"
0
1
true
我如何更改该if...fi
语句,使第一个仅返回true
,第二个返回false
?如果我echo 1
用exit
inside 替换,那么终端窗口就会关闭。
答案1
循环的退出状态是其中执行的最后一个命令的退出状态,它是echo
或break
,并且两者的退出状态通常都是 0。因此,您需要保存并检查条件的状态。我建议使用一个函数:
loopcheck() {
for cond in {0,1,0}; do
if [[ $cond = 0 ]]; then
echo 0;
else
ret=$?; # preserve exit status of test
echo 1;
return $ret; # pass it on
fi;
done
}
loopcheck && echo "true" || echo "false"
另一种选择是$ret
像上面一样保存并在循环外检查其值。
答案2
我拿这优于其他答案(尽管有用),因为它更接近问题中隐含的要求:
$ (for cond in {0,1,0}; do if [[ $cond = 0 ]]; then true; else false; exit; fi; done) && echo "true" || echo "false" false
答案3
循环for name in ...
中继最后执行的命令的退出状态。
当您break
进行循环时,break
默认情况下命令本身的退出状态为 0,因此由 中继for
,从而使您在 be&&
后的测试done
等于true
。
解决这个问题的一种方法就是正如您在自我回答中所说的那样。这是一个漂亮、干净的 shell,并且可以与任何 POSIX 兼容的 shell 很好地配合。
但它有一个缺点,因为作为子 shell,它不能完全共享其功能执行环境1及其“外”壳。它确实在开始执行时继承它,但在完成执行时不会将其“传播”回其“外部”父级,这意味着例如在循环内设置或修改的任何变量在循环外后都不会被看到。
对于 Bash 来说,有一个替代方案:您可以避免使用子 shell 并仍然使用,break
同时通过向其传递参数来强制其失败-1
,因为-1
要退出的循环数量始终是无效的。 Bash 将显示一条错误消息,但您可以通过重定向到 来将其静音2>/dev/null
。
但还要注意,此行为不完全符合 POSIX 标准,因为break
它被视为特殊内置,以及引发错误的“特殊内置”应该退出非交互式壳(例如脚本)。
1[...]。对以下内容所做的更改子外壳环境不能影响贝壳的执行环境。 [...]