2

The POSIX shell standard gives three exceptions to the application of set -e:

  1. 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.
  2. 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.
  3. 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.

I'm struggling to understand the meaning of (3); is it referring to something like:

set -e { false; } && : ( false ) && : 

Here, { false; } is a non-subshell compound command with an exit status of 1. The exit status resulted from the "failure" of false. set -e is being ignored while executing false because it's not the last command of an AND-OR list. The same applies to ( false ), but it's a subshell command, so is set -e allowed to apply to it in the parent shell and thus exit?

This doesn't seem to be the case in actual shells, so I'm pretty sure this example is not what (3) is talking about. After all, it would mean things like if ( false ); then :; fi could exit when executing the if condition. But, it seems the only contexts in which set -e is being ignored are defined by (2), so when then could (3) apply in a logical way?

Essentially, what is an example that clearly demonstrates the meaning of (3), both in what it applies to and why it makes a distinction for subshells?

1 Answer 1

2

I think the "other than a subshell command" means that that entire compound has to be a subshell command.

Compare these:

( false && : ); echo fail #1 { false && :; }; echo pass #2 

The exit status of the false && : is:

  1. the result of a failure (of false)
  2. while -e was being ignored (because it wasn't the last command in an AND-OR pipeline)

But:

  1. The former is for a compound command that is a subshell command, while
  2. The latter is not a subshell command

So the former triggers set -e, while the latter shouldn't.

And:

% for sh in dash bash ksh zsh; do $sh -ec '( false && :; ); echo $0 fail' || echo $sh subshell pass; $sh -ec '{ false && :; } ; echo $0 pass'; done dash subshell pass dash pass bash subshell pass bash pass ksh subshell pass ksh pass zsh subshell pass zsh pass 
2
  • I haven't the faintest idea why this is the case, though. Maybe some earlier shell had a bug in it for subshells that got copied around as expected behaviour and the standard just codified that? Commented Jul 26, 2024 at 2:50
  • Thank you! I missed the idea of the failure coming from a nested compound command. I think POSIX sh was based on the korn shell so it probably was just behavior taken from there. Commented Jul 28, 2024 at 15:41

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.