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 ======================================================================