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

Reply via email to