On 10/11/2024 18:58, Christoph Anton Mitterer wrote:
On Sun, 2024-11-10 at 17:06 +0000, Harald van Dijk wrote:
In dash, the effect of 'set -e' in a
command
substitution is that a command is never considered "tested", unless
that
testing happens inside the command substitution, and it would be
useful
for that to be documented.
The way set -e is currently documented (with "tested" vs. "untested")
in the manpage is IMO already a bit strange.
The way that 'set -e' is currently documented would be useful, but does
not match what is implemented.
Basically: what the current documentation is saying is that every
command gets an implicit "|| exit $?" added to it, unless there is more
specific error handling in the script.
But that is not what POSIX specifies, and what dash implements is closer
to what POSIX specifies, but not exactly what POSIX specifies. The
manpage suggests that
$ dash -c '(set -e; false; echo 123) && echo 456'
would output nothing. Of course, what happens instead, in all shells
that I know of, is that this prints "123" followed by "456".
By POSIX's wording, that's right: "The -e setting shall be ignored when
executing [...] any command of an AND-OR list other than the last." and
there is no denying that that subshell is executing.
By dash's wording that's wrong: the "false" command is not the left hand
operand of an "&&" operator, it's only *part of* the left hand operand
of an "&&" operator.
My personal first preference, which I realise will not and should not be
implemented because it disregards POSIX, would be to leave the
documentation as it is, and adjust dash's behaviour to match the
documentation.
Adjusting the documentation to match the current implementation would be
my personal second choice.
But your text makes it rather even more complicated O:-D
What about something like:
The exit status of a command
+(excluding any commands within command substitutions therein)
is considered to be explicitly tested if the
command is used to control an if, elif
or so...?!
I think the current behaviour would be covered by:
The exit status of a command is considered to be explicitly tested if
the command is used to control an if, elif, while, or until; or if the
command is the left hand operand of an "&&" or "||" operator; or if the
command is part of a list of which the exit status is tested.
I mean AFAIU set -e is NOT ignored only for the commands IN the command
substitution, but IS still ignored for the overall result of the
command substitution (as part of an if, while, etc.).
Correct, 'set -e' is in full effect during command substitutions.
$ dash -ec 'var=$(false; echo foo) || echo foo; var=$(false; echo
bar); echo bar'
foo
Here, the list 'false; echo foo' is (arguably contrary to POSIX) not
considered the LHS of an "||" operator, therefore 'false' causes the
whole subshell to exit, the 'var=$(false; echo foo)' command is
considered to fail, but that command has its exit status tested so
execution continues.
Likewise, the 'var=$(false; echo bar)' command is considered to fail,
that command does not have its exit status tested, so execution stops.
If it's however long standing behaviour of dash (and perhaps
others),
maybe POSIX should instead be revised.
Yes, that would be my preference.
Another "downside" of allowing command substitutions to ignore the
ignoring of set -e is however that things get even more complicated.
I mean it's already crazy enough that for pipelines only the ! negated
ones and for AND-OR lists only all but the last elements are affected
by the set -e ignoring.
Generally excluding command substitutions from all these cases would
make it even more complex to understand and easy to forget while
coding.
IMHO, what dash's manpage currently states is clear and useful, and if
that were actually implemented, the fact that it does not affect
subshells would be a natural consequence, not a special exception.
The difference between treatment of subshells in command substitutions
and subshells outside of command substitutions does make it more
complicated to understand though.
Cheers,
Harald van Dijk