在测试退出状态的上下文中调用时,set -e在函数中被忽略了吗?

时间:2016-02-29 18:11:54

标签: bash

我试图退出shell函数,只要其中运行的任何命令失败,使用set -e

foo () (
    set -e
    echo $SHELLOPTS
    false
    echo set -e failed
)

echo test1:
foo
test $? -ne 0 && echo died

echo
echo test2:
foo && echo died

这是我使用bash 4.2.37获得的输出:

test1:
braceexpand:errexit:hashall:interactive-comments
died

test2:
braceexpand:errexit:hashall:interactive-comments
set -e failed
died

如果foo被称为简单命令( test1 ),则foo会在echo命令之前退出,正如我所期望的那样。但是,如果在复合命令( test2 )中调用,则set -e似乎被忽略,并且继续执行失败的命令。

我知道除了管道的最后一个元素之外,除了-e之外的所有故障都会被忽略,但我不希望如果子shell作为管道的 part 运行如果明确设置,则会覆盖其exiterr状态。请注意,SHELLOPTS表示始终设置errexit,即使在第二次测试中也是如此。

我错过了什么吗?

谢谢,

迪亚布

1 个答案:

答案 0 :(得分:1)

测试1

如果您希望set -E的行为甚至在函数内部应用,请使用set -o errtrace(又名set -e)以及set -e

set -E -e

foo () (
    echo $SHELLOPTS
    false
    echo set -e failed
)

echo test1:
foo
test $? -ne 0 && echo died

echo
echo test2:
foo && echo died

但请注意,如果函数失败,会触发退出,而不是返回。因此,这的输出类似于:

test1:
braceexpand:errexit:errtrace:hashall:interactive-comments:xtrace

...没有更多内容,因为退出立即发生在false

测试2

对于foo && echo died,由于测试了foo的退出状态,因此在执行期间启用了禁用set -e的标志,因此预期此标志的行为已定义为没有效果。

建议

set -e的行为并不直观。在依赖它之前,请确保您完全理解BashFAQ #105中给出的所有行为示例,并考虑阅读the excellent fvue writeup of error handling in bash