The script below has no other purpose than to illustrate this question.
#!/usr/bin/env zsh
arbitrary_pipeline () {
shuf | tr a-z A-Z
}
tmpdir=$( mktemp -d )
mkfifo $tmpdir/{orig,alt}
{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &
pid=$!
paste $tmpdir/orig $tmpdir/alt
rm -rf $tmpdir
wait $pid
The script uses tee and two named pipes to split some (arbitrary) standard input into two streams, redirects one of them to an arbitrary pipeline, and passes the resulting two streams the inputs to paste. Schematically:
STDIN --- > --.- arbitrary_pipeline -.
\ \
paste `----<FIRST-ARGUMENT> `- <SECOND-ARGUMENT> --> STDOUT
(In this case arbitrary_pipeline just shuffles its stdin, and converts it to uppercase, but, as the name implies, it could be anything.)
The script's stdout output looks fine, but the wait command always fails:
% grep -iP 'z.*s.*h' /usr/share/dict/words | /tmp/test.sh
Nietzsche CITIZENSHIP'S
Zubeneschamali NIETZSCHE
Zubeneschamali's ZUBENESCHAMALI
citizenship CITIZENSHIP
citizenship's ZUBENESCHAMALI'S
/tmp/test.sh:wait:18: pid 26357 is not a child of this shell
What am I doing wrong?
FWIW:
/usr/bin/env zsh --version
# zsh 5.0.7 (x86_64-pc-linux-gnu)
EDITS:
- added curly braces around the
teepipeline, per jordanm's suggestion. (Results did not change, though.) - replaced
&!with&in response to Stéphane Chazelas' comment. (Again, results did not change.)
{ tee $tmpdir/orig | arbitrary_pipeline > $tmpdir/alt; } &&!is explicitely to disown the job! Of coursewaitwill fail, that's what&!is for. Use&instead of&!if you still want the shell to consider the job as its child so you can wait for it.&alone. (I will edit my post to eliminate my stupid red herring.)