set -e; ( false; echo qwe; ) || echo qwe
doesn't do what you think it does:
any subshell (
( ... )
) containing a list of commands (false; echo qwe
) will execute all commands in that list and decide based on the last command's exit code whether to abort the subshell (due to-e
); sinceecho qwe
, as the subshell's last command returns0
as its exit code (signaling succcess), the subshell returns0
overall, and so the right side of||
never kicks in; try with distinct strings to echo:set -e; ( false; echo qwe1; ) || echo qwe2
Trying to set a variable (
ret
, in this case) in a subshell for access in the originating shell is always pointless, because its scope will be confined to that subshell; to pass a value out from a subshell, usestdout
output.
To achieve your goal, forget about set -e
and instead suffix each command in the subshell with || exit
in order to abort right away in case of failure; the exit code on leaving the subshell will then correctly reflect the exit code of the first failed command, or 0
, if all commands succeeded:
output=$( false || exit; echo qwe || exit ) # capture output from subshell
ret=$? # $? reflects overall success of subshell