The following issue has been SUBMITTED. 
====================================================================== 
https://austingroupbugs.net/view.php?id=1879 
====================================================================== 
Reported By:                calestyo
Assigned To:                
====================================================================== 
Project:                    1003.1(2024)/Issue8
Issue ID:                   1879
Category:                   Shell and Utilities
Type:                       Clarification Requested
Severity:                   Editorial
Priority:                   normal
Status:                     New
Name:                       Christoph Anton Mitterer 
Organization:                
User Reference:              
Section:                    Shell Command Language 
Page Number:                various 
Line Number:                various 
Interp Status:              --- 
Final Accepted Text:         
====================================================================== 
Date Submitted:             2024-11-26 04:30 UTC
Last Modified:              2024-11-26 04:30 UTC
====================================================================== 
Summary:                    claifications/improvements around command/exec and
special built-in redirection errors
Description: 
Hey.


1)

The 2018 edition said for the exit status of the exec special built-in:
> If a redirection error occurs (see Consequences of Shell
> Errors), the shell shall exit with a value in the range 1-125.

with 2.8.1 Consequences of Shell Errors of the 2018 edition also saying
that:
"Redirection error with special built-in utilities" … "shall exit" in
"Non-Interactive
Shell[s]" and "shall not exit" in "Interactive Shells"

IMO that was already ambiguous, as the former *generally* said "shell shall
exit" but the latter only for the non-interactive case.


With the 2024 that got IMO even more ambiguous:
2.8.1 Consequences of Shell Errors stayed the same (for Redirection error
with
special built-in utilities), but the exit status for exec is now described
as:
> If a redirection error occurs (see 2.8.1 Consequences of Shell
> Errors ), the exit status shall be a value in the range 1-125. 

In particular it no longer says "the shell shall exit", but rather talks
about an exit status (using the same wording it uses in other places for
regular exit statuses where the shell doesn't abort per se).




2)
The `command` utility says:
> If the command_name is the same as the name of
> one of the special built-in utilities, the special
> properties in the enumerated list at the beginning
> of 2.15 Special Built-In Utilities shall not occur.

These properties in turn are:
> 1. An error in a special built-in utility may cause
>    a shell executing that utility to abort, while an
>    error in a regular built-in utility shall not cause
>    a shell executing that utility to abort. (See 2.8.1
>    Consequences of Shell Errors for the consequences of
>    errors on interactive and non-interactive shells.)
>    If a special built-in utility encountering an error
>    does not abort the shell, its exit value shall be non-zero.
> 2. <not important here>

The above says, that (1) and (2) shall NOT occur when `command`-utility is
used.
But what exactly does that mean for (1)?
(1) says "error in a special built-in utility may cause a shell executing
that utility to abort"... but are these errors ONLY the "Special built-in
utility error" mentioned in the table in 2.8.1. or are they ALSO the
"Redirection error with special built-in utilities" from the same table.

The former, I'd interpret this as:
While (non-interactively) `set -Q` (-Q does not exist) causes the shell to
abort, but `command set -Q` doesn't do so, as in e.g.:
  $ dash -c 'set -Q; echo foo'
  dash: 1: set: Illegal option -Q
  $ dash -c 'command set -Q; echo foo'
  dash: 1: set: Illegal option -Q
  foo
  $

The latter, I'd interpret as (the above plus), I can NOT do:
  exec 1>/does-not-exist/file || es=$?
but CAN do:
  command exec 1>/does-not-exist/file || es=$?
to capture the exit status of the exec, and not have the shell abort.

Again, this would be the behaviour of at least dash:
  $ dash -c 'exec >/does-not-exist/file || es=$?; echo es: $es>&2'
  dash: 1: cannot create /does-not-exist/file: Directory nonexistent
  $ dash -c 'command exec >/does-not-exist/file || es=$?; echo es: $es>&2'
  dash: 1: cannot create /does-not-exist/file: Directory nonexistent
  es: 2
  $

This goes along with the changes from issue #1427, which added the
following note #1 to 2.8.1:
> The shell shall exit only if the special built-in utility
> is executed directly. If it is executed via the command
> utility, the shell shall not exit.

But ONLY, to the "Special built-in utility error" row. So either it was
forgotten for the "Redirection error with special built-in utilities" or
it's indeed NOT meant for redirection errors (but then see (3))




3) Why I think, redirection errors in at least `exec` should be ignored
with `command`?!
I've stumbled over this whole issue when I saw a question on help-bash,
which effectively was:
  How can one differentiate the exit status from the
  utility from an error exit status that resulted from
  redirection errors?

A simple example:
In
  grep foo </does-not-exist/file
it's unclear whether the pattern was not matched (grep exit status 1) or
whether a redirection error occurred, in which case bash uses e.g. also
exit status 1.

The original poster of the question proposed a solution like:
  ( exec </does-not-exist/file || exit 100; grep foo )
where the application would need to make sure that 100 is an exit status
not used by grep.

This seems to work in bash, but only because that seems to not abort on
redirection errors (per default):
  $ bash -c '( exec </does-not-exist/file || exit 100; grep foo )' ; echo
$?
  bash: line 1: /does-not-exist/file: No such file or directory
  100
  $ bash --posix -c '( exec </does-not-exist/file || exit 100; grep foo )'
; echo $?
  bash: line 1: /does-not-exist/file: No such file or directory
  1
  $ dash -c '( exec </does-not-exist/file || exit 100; grep foo )' ; echo
$?
  dash: 1: cannot open /does-not-exist/file: No such file
  2
  $

AFAICS, the only[0] portable solution would be using command, i.e.:
  $ bash -c '( command exec </does-not-exist/file || exit 100; grep foo )'
; echo $?
  bash: line 1: /does-not-exist/file: No such file or directory
  100
  $ bash --posix -c '( command exec </does-not-exist/file || exit 100; grep
foo )' ; echo $?
  bash: line 1: /does-not-exist/file: No such file or directory
  100
  $ dash -c '( command exec </does-not-exist/file || exit 100; grep foo )'
; echo $?
  dash: 1: cannot open /does-not-exist/file: No such file
  100

But honestly, I'm not even sure whether this is intended now by POSIX
(given that it's not clear whether the no-abort property of `command`
applies to special built-in redirection errors or not),... and even if it
would, I'm still not sure whether the above is really functioning in any
possible context (like in subshells/command substitutions, with set -e, set
-e ignoring contexts, ugly PATHs, or whatever).
Though I'd guess so; maybe some expert can confirm or deny.


[0] It might be possibly to do some very ugly hacks without `command exec`
but just `exec` in subshells... since then only those should abort on a
redirection error. But that wouldn't be really practical IMO.
Desired Action: 
1) I assume a redirection error in plain exec in a non-interactive shell is
still intended to cause the shell to abort/exit with an error (IIRC, bash
doesn't do this).
If so, the "Exit Status" section should be somehow improved to better
reflect that.
Perhaps simply like:
> If a redirection error occurs, the exit status
> shall be a value in the range 1-125 with the
> consequences given in 2.8.1 Consequences of Shell Errors.

But perhaps this should even be expanded to mention the note #1 in 2.8.1.,
i.e. that the consequences don't apply if `exec` is called as `command
exec`.




2) Depending on whether or not ,`command <special built-int>` should also
cause special built-in redirection errors to not cause the shell to exit:

a) clarify in the description of the `command`-utility and/or the list item
#1 in 2.15 Special Built-In Utilities, that redirection errors with special
built-ins are included or explicitly mention that this is not the case.
Beware, that if doing so in the 2.15, it might affect far more things than
just `command`.

b) Add (or don't add) the ¹ note superscript to the "shall exit" for
"Redirection error with special built-in utilities".




3) IMO having a way to differentiate between a redirection error and a
utility error is quite important.

a) This would be my case for requesting the behaviour to be specified as
such (unless that's anyway intended), barring of course any shell
implementations would already behave different.

b) I know, the standard is no teaching document, but it nevertheless gives
many valuable examples. So I'd ask to consider whether it would make sense
to find some place in the rationale of perhaps `exec` or `command` or maybe
even in the Redirections chapter, where something like:
  ( command exec </does-not-exist/file || exit 100; grep foo )

could be shown as a way how to differentiate between utility and
redirection error, or better said: how one can alter the exit status the
shell uses in case of an error of a redirection that gets applied to some
command.

btw:
Not really sure whether there's a way to also filter the error message from
the redirection error.
  (  { command exec </does-not-exist/file || exit 100; } 2>/dev/null;  grep
foo  )
but this might of course then fail+abort (at least in principle) when
redirection to /dev/null.
While:
  (  command exec </does-not-exist/file 2>/dev/null || exit 100;  grep foo 
)
does not work and:
  (  command exec 2>/dev/null </does-not-exist/file  || exit 100;  grep foo
 )
does seem to work (and I guess the latter should work portably), they'd
have of course the downside of also swallowing any stderr from grep.

Interestingly, this is also caused by the upper "solution":
$ dash -c '(  { command exec </does-not-exist/file || exit 100; }
2>/dev/null;  grep --sdsd foo  )' ; echo $?
100

Not really sure why, TBH.


Thanks.
====================================================================== 

Issue History 
Date Modified    Username       Field                    Change               
====================================================================== 
2024-11-26 04:30 calestyo       New Issue                                    
2024-11-26 04:30 calestyo       Name                      => Christoph Anton
Mitterer
2024-11-26 04:30 calestyo       Section                   => Shell Command
Language
2024-11-26 04:30 calestyo       Page Number               => various         
2024-11-26 04:30 calestyo       Line Number               => various         
======================================================================


  • [1003.1(2024... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group
    • [1003.1... Austin Group Bug Tracker via austin-group-l at The Open Group

Reply via email to