有建议使用以下选项使Bash快速失败:
set -o errexit
set -o nounset
set -o pipefail
然而,这些选项无法按预期通过||
管道传输Bash功能。
E.g。在脚本中
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail
my_function() {
test -z "$1"
echo "this SHOULD NOT be printed"
}
my_function 1 || echo "???" # 1
my_function 1 # 2
echo "this will not be printed"
行# 2
将导致脚本在没有任何输出的情况下以代码1终止。这就是我的期望。
行# 1
实际上让我困惑:my_function
将成功完成,打印“不应该打印”并返回代码0,因此“???”将不会被打印。
如何让Bash在my_function
行# 1
处理同样的失败快速方式,就像在线# 2
一样?
答案 0 :(得分:6)
还有更好的建议not to use set -e
/errexit
:
显然,当条件(在
if [ -d /foo ]; then
中)返回非零时,我们不想中止。 [...]实现者决定制定一系列特殊规则,例如“if if test的一部分命令是免疫的”,或者“管道中的命令,除了最后一个,都是免疫的”。这些规则非常复杂,甚至连一些非常简单的案例仍然无法捕捉到。更糟糕的是,规则从一个Bash版本变为另一个版本,因为Bash试图跟踪这个“特征”的极度滑落的POSIX定义。当涉及SubShell时,它会变得更糟 - 行为会根据是否在POSIX模式下调用Bash而改变。
如果脚本在非零返回时停止,foo || bar
也将无用,因为bar
永远不会运行(脚本会退出)。因此,其中一个复杂的规则是&&
或||
左侧的命令中的非零返回不会导致脚本退出。这就是你所看到的效果。
无法使set -e
正常工作且无法自动替换。如果不编写手动错误处理,就无法按照自己的方式工作。
答案 1 :(得分:2)
查看bash手册,以下是trap
命令的内容:
trap [-lp] [arg] [sigspec …]
如果sigspec是ERR,则只要管道(可能包含单个简单命令),列表或复合,就会执行命令arg 命令返回非零退出状态,具体取决于以下内容 条件。如果失败的命令是部分,则不执行ERR陷阱 紧跟在until或while关键字后面的命令列表, 部分测试遵循if或elif保留字,a。的一部分 命令在&&amp ;;中执行或||列表除了后面的命令 最终&&或者||,管道中的任何命令,但是最后一个,或者如果是 使用!来反转命令的返回状态。这些都是一样的 errexit(-e)选项遵守的条件。
特别是看最后一句话。这解释了它!