6

This question already has an answer here:

When cat is given two heredocs, it only outputs the second one.

$ cat <<HERE
> adsf
> qwer
> HERE
adsf
qwer
$ cat <<HERE <<ALT
> qwer
> asdf
> HERE
> zxcv
> yuop
> ALT
zxcv
yuop

This also applies if given a heredoc and a file, atlhought I notice that if I give it a file and a heredoc (reversed order), it still only outputs the file. However, if I gave cat two files, it correctly outputs both of them.

Why does cat behave this way?

marked as duplicate by user34720, Anthon, don_crissti, jasonwryan, Ramesh Apr 2 '15 at 20:36

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

3

There are a number of ways of redirecting a command's standard input (stdin):

  • command <file Simple redirection: stdin will be the file
  • command <&n Duplicate other fd: stdin will be a duplication of fd n
  • command <<word Here doc: stdin will be the script up to word
  • other | command Pipe: stdin comes from the output of other

Since there is only one stdin, only one redirection to stdin can be effective. The simple rule is that the last one wins (although all of them are applied in turn, which is important if the redirects include fd duplication).

The last form above provides a simple way to concatenate multiple inputs:

{ cat <<END; cat <<END; } | command
The first here-doc
END
The second here-doc
END

Some shells provide additional redirection forms. For example, bash, ksh and zsh allow provide "here-strings": command <<<word.

  • To add to the list: ... >(command) (process substitution, command's stdin is a pipe, expands to the other end as a file name), coproc command/command |& (coproc), zpty C command (coproc with pty). – Stéphane Chazelas Apr 2 '15 at 16:11
8

On systems with /dev/fd/x:

cat - << E0 /dev/fd/3 3<< E3
foo bar
E0
bar baz
E3

That is, open the two here documents on different file descriptors. If you open them both on fd 0, of course the last open overrides the previous ones.

The above would be more useful with commands like paste though.

Note that zsh has the MULT_IOS feature (enabled by default and disabled with unsetopt MULT_IOS or when emulating other shells) whereby if you redirect a file descriptor for input more than once, zsh feeds instead the concatenation of the corresponding inputs (via a pipe in a separate process). So in zsh:

$ cat << E1 << E2
heredoc> foo
heredoc> E1
heredoc> bar
heredoc> E2
foo
bar

cat's stdin is a pipe then and zsh feeds the content of the two here documents in sequence at the other end of the pipe.

There a similar feature for output redirection.

ls > a > b

makes ls write to a pipe and zsh writes to a and b concurrently (like a form of tee) while in other shell's ls's stdout would just be b (and a would have been truncated but never written to).

  • Thanks for the hint pointing me towards the functionality of something like cat file1 - file2 <<EOT | mail .... – Dave X Aug 1 '17 at 16:11
5

cat without any args will read its standard input (i.e. file descriptor 0) until end of file, and copy that to its standard output (i.e. file descriptor 1).

cat with one or more args will try to open those args in turn as its input, and copy the data to its standard output. It ignores the standard input in that case, which is a good thing as it would become quite irritating to have to type ctrl+D after doing e.g. cat /etc/motd. This explains why cat is ignoring the "here" document when also given a filename. As a special case you can supply - as a filename which is interpreted as meaning "standard input" -- that wy you can combine a file with a "here" document.

The shell can only pass one file as standard input to a command, so it doesn't make much sense to pass two "here" documents to one command; only the last one will actually make it as standard input for the command.

1

I have no idea where it can be usefull but:

cat <<HERE
qwer
asdf
$(cat <<ALT
zxcv
yuop
ALT
)
HERE

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