为什么 Bash errexit (`set -e`) 没有传递到命令替换 `$()` 子 shell 中,而是传递到 `()`-subshell 中

问题描述 投票:0回答:1

我正在努力解决为什么 errexit 又名

set -e
没有传递到命令替换子 shell(使用
$(my-command)
或反引号调用),而是传递到常规子 shell(使用
(my-command)
调用)。

这个例子:

#!/usr/bin/env bash

set -e
# or:
#set -o errexit

foo() {
    echo "foo()" >&2

    # Fetch output of actual command, in real life this could be something like
    # and fail because you're not authorized or something
    #somevar=$(curl --fail --silent "restapi.example.com/get-stuff")
    somevar=$(echo foo; exit 42)

    echo "foo() after subcommand, exit code: $?" >&2  # this resets $?
    echo "foo() last exit code: $?" >&2
}

echo '=== Run in $() ===' >&2
a=$(foo)  # runs past this point
echo "code: $?" >&2

echo "=== Run in () ===" >&2
(foo)  # fails
echo "code: $?" >&2

echo "=== Run directly ===" >&2
foo  # fails
echo "code: $?" >&2

这种行为对我来说有点奇怪,因为这完全没有意义..进一步测试这一点:

#!/usr/bin/env bash

set -e
# or:
#set -o errexit

echo '=== Run 1 ===' >&2
a=$(b=$(exit 42); echo "möp")
echo "code: $?" >&2

# echo '=== Run 2 ===' >&2
# a=$(b=$(exit 43))  # fails without reset of $?
# echo "code: $?" >&2

echo '=== Run 3 ===' >&2
a=$((exit 44); echo "möp")
echo "code: $?" >&2

echo '=== Run 4 ===' >&2
a=$((exit 45))  # works regardless of not resetting $?
echo "code: $?" >&2

# echo '=== Run 5 ===' >&2
# a=$(exit 46; echo "möp")  # fails
# echo "code: $?" >&2

# echo '=== Run 6 ===' >&2
# (exit 47; echo "möp")  # fails
# echo "code: $?" >&2

# echo '=== Run 7 ===' >&2
# ((exit 48); echo "möp")  # fails
# echo "code: $?" >&2

(注释掉的测试将在此时停止脚本)

我想知道为什么它会这样,以及这是否是一个错误。我自己对此有足够的解决方法,并且无论如何,围绕这些命令编写更多的故障保护可能会更聪明(特别是如果这实际上是针对 REST API 的卷曲,其中更多的事情可能会出错),但是为什么 bash 的行为像这样?

测试

  • 4.4.20
  • 5.2.32
bash error-handling exit-code subshell command-substitution
1个回答
0
投票

您需要

shopt -s inherit_errexit
才能通过命令替换继承选项。请参阅内置 Shopt

inherit_errexit
If set, command substitution inherits the value of the errexit option, 
instead of unsetting it in the subshell environment. This option is 
enabled when POSIX mode is enabled.
© www.soinside.com 2019 - 2024. All rights reserved.