A long time ago ... in a dark collage basement, I discovered that /bin/sh did a weird thing with pipelines. In the pipeline
a | b | c
it is the LAST segment ("c") which is run in the current shell, and "a" and "b" are in forked processes. I always found this somewhat strange until I realized this syntax actually works
echo foo | read a
Because "read a" is executed in "this" shell,
$ echo $a
foo
Try this in bash or other "modern" shells and it doesnt work.
I wonder why noone noticed ? I just tried in a modern linux FC8 ksh and voila ! That wonderful legacy behaviour works !
[dave@home ~]$ ksh
$ echo foo | read a
$ echo $a
foo
But unfortunately xmlsh is different then bash OR ksh .. it runs all commands in a sub thread/shell. Does anyone have any opinions on how useful or important this somewhat arcane behavior is ? It definitely has some use cases, but I wonder why bash authors didn't deem it important enough to preserve.
In xmlsh it may be even more useful, consider this in a script
xslt ... | xquery ... | xread DOC
This cant be implemented easily otherwise ...
DOC=$<(xslt ... | xquery ... )
since the $<( ) syntax doesnt read from stdin, you'd have to do
xread DOC1
DOC=$( echo $DOC1 | xslt ... | xquery ...}
I guess this is back to the forking question ...
I have changed the implementation to run the last command in a pipeline to run in the current shell. This reference
ReplyDeletehttp://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_10
Section 2.9.2 has a hint that this is the expected behaviour but it doesnt totally spell it out. It covers the exit status of the last command:
"If the reserved word ! does not precede the pipeline, the exit status shall be the exit status of the last command specified in the pipeline. Otherwise, the exit status shall be the logical NOT of the exit status of the last command. That is, if the last command returns zero, the exit status shall be 1; if the last command returns greater than zero, the exit status shall be zero."
This syntax now works
$ echo foo | read a
$ echo $a
foo