When cat
is not given a filename on the command line (or if the filename is just -
), then it switches to reading from its standard input.
That means that with
cat <<END
something something
END
cat
will notice that it was not given a filename and will proceed to read from the here-document, which is arriving on its standard input stream.
You can get cat
to read from both its standard input and from a file with
cat - filename <<END
something something
END
This will cause the contents of the here-document to be concatenated with the contents of filename
. If the order of the arguments was filename -
then that would be the order that the data would be concatenated too.
Note that -
is not special to the shell in any way, and is interpreted as "standard input" specifically by the cat
utility (and a few others). If you have an actual file called -
that you need to run cat
on, use cat ./-
, i.e. specify the filename with a path.
For all purposes, you can think of feeding a here-document directly into a utility as a shorthand for creating a temporary file and then invoking the utility with that attached to the standard input stream:
printf 'some contents' >tmpfile
utility <tmpfile
rm -f tmpfile
Here-documents might not actually be implemented this way (it may be a FIFO (named pipe)), but that's not an entirely incorrect way of thinking about it.
Reading the bash
sources, it seems as if that particular shell implements here-documents by creating a temporary file using the mkstemp()
library function if it's available, otherwise it tries to create a random filename to write to. The contents of the document is then written to that file and the data is provided on the standard input of whatever it is that's reading it, just as if it came from a file, redirected with <
. See redir.c
and lib/sh/tmpfile.c
in the bash
source distribution.