Bash Zsh Pipe – Why Is stdout from the First Command in This Pipe Not Being Processed?

bashpipezsh

I'm trying to write a command that can simultaneously (i) read from stdin and (ii) read from a pipe. This basic concept works in zsh, but not in bash. The following session illustrates the difference in behavior for the two shells:

$ echo bar > bar
$ zsh -f
zsh-5.8$ echo foo | cat < bar
foo
bar
zsh-5.8$ exit
$ bash --noprofile --norc
bash-5.0$ echo foo | cat < bar
bar

I can see that the above commands give cat two sources of stdin (the pipe and the redirect), so perhaps it's ambiguous how that should be handled. zsh seems to concatenate the two input streams, with the piped input consistently coming first. bash seems to simply drop the piped input.

My questions are:

  1. Why do the two shells behave differently?
  2. Is there any way to force bash to behave like zsh?

Best Answer

As you have noticed, the MULTIOS shell option in zsh is what makes this possible. There is no similar built in facility in the bash shell.

In bash, you would get the same behavior (for this particular example; see Uncle Billy's comment below) from

echo foo | { cat; cat bar; }

or

echo foo | cat - bar

Both of these right hand sides first read their standard inputs before reading bar.

Related Question