|
|
The Answer Gang 96: Linux "read" issue
Linux "read" issue
From Sanford, Kurt
Answered By: Jim Dennis
Hi Jim and Dennis,
Actually, "Jim Dennis" is one person, and the original founder of the
Answer Gang....
-- Thomas Adam
Regarding the problem with:
echo 1 2 3 | read a b c
echo $a $b $c
on Linux ksh (see http://linuxgazette.net/issue57/tag/1.html
<http://linuxgazette.net/issue57/tag/1.html> ), why are Red Hat and
SuSe using such an old version of ksh? That version of ksh must be
quite old because I have been writing UNIX ksh scripts that do "echo 1 2
3 | read a b c" since at least 1996. Why hasn't the Linux version of
ksh been updated?
[JimD]
I think you misunderstand my point. Some shells read run the implicit
subshell to the right of the pipe (bash, older versions of ksh, etc)
while others run it on the left (newer ksh and zsh).
As far as I know POSIX doesn't specify which behavior is correct.
Therefore the authors of each shell are left to their own judgement for
their own implementations. I personally believe that the new ksh and
zsh semantics are better and provide for cleaner shell scripting code.
The test for any Bourne compatible shell to disambiguate one set of
semantics from the other:
unset foo; echo bar | read foo; echo $foo
If that prints nothing but a blank line, you're running ash, bash, or
and old pdksh or other Bourne shell. If it prints "bar" then you're
running Korn '93(?) or newer, or zsh.
Notice that, around any pipe operator in any shell command there is an
implicit subshell (child process). The pipe is an inter-PROCESS
communications mechanism so there have to be a pair of processes as the
writer and reader to and from the pipe. We're simply asking which side
of the pipe is handled in the sub process and which is handled in the
current process.
Also note that in many cases (when the commands to either side of the
pipe are external) the whole issue is moot. Both will be in child
processes:
cat ./foo | less
... since cat and less are both external commands both are in
subprocesses of the current shell and it doesn't matter what order
the forks were in.
The shell will create one subshell (child process), that will create
the pipe (using the pipe system call) and dup them to stdin and stdout,
then it will create another subshell/process. The (first) child will
then close one of the ends of the pipe (either the read or the write)
and the (second) grandchild will close the other. Then one of them
(with the write end of the pipe still open) will exec*() the cat command
while the other (on the read end of the pipe will exec the less command.
There may be other sequences of system calls that net comparable
results. You could run strace on a number of shells to see.
Copyright © 2003
Copying license http://www.linuxgazette.net/copying.html
Published in Issue 96 of Linux Gazette, November 2003
|