2017-08-14 10:03:52 +0100, Geoff Clare: [...] > > All shells I tried output to "c" there, which to a user can be > > confusing. Maybe the mechanism should be specified somehow in > > the spec, like a note in the description of the "exec" utility. > > Not sure of the best way to express it though. > > I think the introductory part of 2.7 Redirection is probably the best > place to talk about restoring the previous state of file descriptors > on completion of a redirected command. I think it should apply to any > command that is not described in 2.9.1.1 (or 2.9.1.2 after bug 1157 is > applied) as being executed in a separate utility environment. [...]
True, but "exec" is the one command where that redirection behaviour can cause surprises. So while I agree the behaviour should be described when describing the redirection of compound commands, builtins and functions (redirections of things that don't run in subshells/child processes), it would be useful to add a note in the description of the "exec" special builtin, as that's a case where "exec"'s action is being cancelled. In the Bourne shell, redirecting a compound command implied forking a subshell, so the: { exec > a; } > b wasn't ambiguous. It was clear the "exec > a" only affected the stdout of that subshell. In SVR2, functions were added and the ability to redirect those as well as builtins. Redirecting builtins and functions was not spawning a subshell, though redirecting compound commands still did. Other than that, it was behaving mostly like the Korn shell. In particular, out() { exec > "$1"; } out file.out would redirect stdout to "file.out", but: out file.out > /dev/null Would end up leaving stdout untouched. Like in ksh, the fork is avoided by saving the original destination of the redirected fd onto a fd above 10 (fcntl(fd, F_DUPFD, 10)) and restoring afterwards. That's what you would do by hand in the Bourne shell to avoid the subshell. Instead of: while ...; do ... done < file (which would run the loop in a subshell), you'd do: exec 3<&0 < file # original stdin saved on fd 3 while ...; do ... done exec <&3 3<&- # restore stdin Now, ksh (or the Bourne shell for functions/builtins) does the same but internally and on a fd above 10 and with the close-on-exec flag, so cleaner. But as that's now hidden to the user, the fact that it affects the behaviour of "exec" is not as obvious. -- Stephane