3

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?
  • 1
    1. Because they're different shells and the operation (AFAIK) has no POSIX definition. 2. No. – roaima Apr 6 at 23:30
  • @roaima I don't think your claim 1. is correct. Do you have any reference? I think that in a POSIX shell, the cat should only read from bar in echo | cat < bar, and the MULTIOS feature in zsh makes it not standard compliant. – Uncle Billy Apr 7 at 2:38
  • 1
    @roaima Just like nobody knows that there isn't a teapot orbiting the sun, right? It's you who made the assertion that a redirection in a pipeline is undefined behaviour in POSIX, you should prove it. – Uncle Billy Apr 7 at 8:04
  • 1
    @UncleBilly I've made no assertion that the pipeline is undefined behaviour in POSIX. I said (1) that as far as I knew there was no POSIX definition for reading stdin from two different sources, (2) that I couldn't find a POSIX statement (either way). If I had a definitive statement I would have written a proper answer citing the source. – roaima Apr 7 at 8:40
  • 1
    @roaima It's specified in Section 2.9.2 of the POSIX Shell Command Language pubs.opengroup.org/onlinepubs/009695399/utilities/… The standard input, standard output, or both of a command shall be considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command – Barmar Apr 7 at 16:07
4

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.

| improve this answer | |
  • The link from your answer explicitly mentions that Multios behaves differently from cat: "each file is opened immediately, not at the point where it is about to be read: this behaviour differs from cat". And indeed, even such simple examples as those from you answer will behave differently if bar is a fifo or an unreadable file. – Uncle Billy Apr 7 at 8:22
4

I spent some more time looking at this, and I found that the behavior of zsh is due to the MULTIOS option, which is enabled by default. bash doesn't seem to have a comparable option, so this behavior is specific to zsh.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.