Subshell created using (...) behaves differently from bash -c '...' Subshell created using (...) behaves differently from bash -c '...' unix unix

Subshell created using (...) behaves differently from bash -c '...'


The behavior of set -e with && is intentional.

It explicitly doesn't trigger when the command is part of a && sequence.

From the POSIX spec:

-e

When this option is on, when any command fails (for any of the reasons listed in Consequences of Shell Errors or by returning an exit status greater than zero), the shell immediately shall exit with the following exceptions: The failure of any individual command in a multi-command pipeline shall not cause the shell to exit. Only the failure of the pipeline itself shall be considered.

The -e setting shall be ignored when executing the compound list following the while, until, if, or elif reserved word, a pipeline beginning with the ! reserved word, or any command of an AND-OR list other than the last.

If the exit status of a compound command other than a subshell command was the result of a failure while -e was being ignored, then -e shall not apply to this command.

This requirement applies to the shell environment and each subshell environment separately. For example, in:

set -e; (false; echo one) | cat; echo two

the false command causes the subshell to exit without executing echo one; however, echo two is executed because the exit status of the pipeline (false; echo one) | cat is zero.

I assume the difference here then is whether the shell knows that fact.

(...) presumably does because the current shell executes it and bash -c presumably doesn't because that's a fully external process (or something).

That last bit is speculation and to my mind the sub-shell behavior here is entirely unhelpful and makes set -e unreliable (which is why many people suggest avoiding it).

Though it seems like this might also provide a sort of "escape hatch" for that reliability problem if an explicitly run shell doesn't have that issue with composition of scripts.