Por que o Bash não passa a opção errexit para substituir comandos?

Por que o Bash não passa a opção errexit para substituir comandos?

Opções de shell definidas porsetconstruídas emsão herdados em sub-shells (pelo menos o errexit). Isto pode ser provado por:

set -o errexit

function foo() {
    echo "foo:$BASHPID"
    false
    echo 'after' 
}

echo "main:$BASHPID"
( foo )

No entanto, as opções não parecem herdadas emsubstituição de comando, que também devem ser subshells de acordo com a documentação do Bash. Prova:

set -o errexit

function foo() {
    echo "foo:$BASHPID"
    false
    echo 'after' 
}

echo "main:$BASHPID"
output=$(foo)
echo "output: $output"

Resultado esperado:

main:123
output: foo:124

Saída real:

main:123
output: foo:124
after

Isso é esperado ou um bug?

Responder1

Sim, é esperado que, quando não estiver no modo POSIX (como ao executar as sh), o bash redefina errexitdentro das substituições de comando por padrão.

Se você deseja errexitser preservado nas substituições de comandos, com bash 4.4 ou mais recente, use:

inherit_errexit

Se definido, a substituição do comando herda o valor da errexitopção, em vez de desmarcá-la no ambiente subshell. Esta opção é habilitada quando o modo POSIX está habilitado.

(DeManual do Bash.)Outra parte da documentaçãotornou mais explícito:

A ativação do modo POSIX tem o efeito de definir a inherit_errexitopção, portanto, os subshells gerados para executar substituições de comando herdam o valor da -eopção do shell pai.Quando a inherit_errexitopção não está habilitada, o Bash desmarca a -eopção nesses subshells.

Verificar:

$ bash -o errexit -c 'echo "$(echo "$SHELLOPTS")"'
braceexpand:hashall:interactive-comments
$ bash -o errexit -O inherit_errexit -c 'echo "$(echo "$SHELLOPTS")"'
braceexpand:errexit:hashall:interactive-comments

No bash 4.2 e anteriores, errexitera exibido no primeiro, mas ainda efetivamente desativado:

$ bash-4.2 -o errexit c 'echo "$(false; echo "$SHELLOPTS")"'
braceexpand:errexit:hashall:interactive-comments
$ bash-4.2 -o posix -o errexit -c 'echo "<$(false; echo "$SHELLOPTS")> $?"'
<> 1

informação relacionada