Consider the following command:
seq 5 | grep $(tail -n1) <(seq 9)
When running it in zsh
1:
tail: error reading 'standard input': Input/output error
Now running the same in bash
, it outputs:
5
OK. As explained in the comments, the command substitution $(tail -n1)
inherits stdin
from its parent. But why doesn't that happen with zsh
?
Is this a zsh
-only thing or is it something that other shells do too ? Where is it documented ?
Now, if I run the same command via zsh -c
:
zsh -c 'seq 5 | grep $(tail -n1) <(seq 9)'
instead of printing the same error message, it stops after tail -n1
and waits for user input so if I type
19
2
4
then hit Ctrl+D, it prints
4
What's going on here ?
1: this is with zsh
5.3.1
on archlinux
, if it matters.
Best Answer
You'll notice that in
bash
/ksh
outputs
foo
butDoesn't.
In the first case, the
$(cat)
is expanded in the child process that will eventually executeecho
after its stdin has been redirected from the pipe.In the second case, the
$(cat)
is expanded before the redirection.pipes and redirections are different things. pipes involve some redirection but also starting commands in parallel. That happens early, before the redirections inside each pipe component.
In
zsh
You'll notice that this time the command substitution is expanded by the parent shell.
One thing to bear in mind is that in
zsh
, pipes are treated a bit more like redirections in particular when it comes to themult_ios
option (enabled by default).When you do:
foo
goes to bothfile
andtr
.In:
cat
is fed both the output ofuname
and the content of/etc/issue
. So inzsh
, redirection from<
/>
and from pipe have to happen at the same stage. Preferably after the expansions.In any case, you can always do:
in both
zsh
andbash
/ksh
like you can always do:in both
bash
andzsh
.As to the cause of the:
error. In interactive shells, since the command substitution is done in the parent, it's not done in the foreground process group of the terminal.
tail
will be run in the process group of the parent shell. If that shell is the session leader, it will be an orphaned process group, so whentail
tries to read from the tty device, it will fail with EIO.If
zsh
was not the session leader. For instance, if you startedzsh
from another shell, then the process group would receive a SIGTTIN. The main shell process would ignore it, buttail
would end up being suspended.