Bash失败了快速功能

时间:2016-12-27 23:45:21

标签: bash

有建议使用以下选项使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一样?

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)选项遵守的条件。

特别是看最后一句话。这解释了它!