Bash – For input redirection, are there functional differences between bash/zsh <<<“$(

bashcommand-substitutionhere-documentio-redirectionzsh

I'm asking only about the usage which would have the similar effect as traditional input redirection from a file.

<<<"$(<file)"

as far as I can tell is equivalent to

<file

It appears to me that these are functionally equivalent. At the low level it appears that the <<< here document might actually cause more copies of the data to be in memory at once.

I know this type of redirection exists in both bash and zsh but I'm not familiar with how it's implemented, though I see the zsh manpages contain some implementation details.

Best Answer

In <<<"$(<file)" (supported by zsh (where <<< was first introduced, inspired by the same operator in the Unix port of rc), ksh93 (the $(<file) operator was introduced by ksh), mksh and bash),

For $(<file), the shell reads the content of the file (chokes on NUL bytes except for zsh), removes all the trailing newline characters and that makes the expansion of $(<file) (so the content of the file is stored as a whole in memory).

For <<< some-text, the shell stores some-text followed by one newline character into a temporary file, and opens that temporary file on the file descriptor 0.

So basically <<<"$(<file)" opens stdin for reading on a temporary copy of file where trailing newline characters have been replaced by just one (and with various misbehaviours if the file contains NUL bytes, except in zsh).

While in < file, it's file that is directly opened for reading on stdin.

Of course < file is much more efficient (doesn't involve a copy on disk and in memory), but one might want to use the <<<"$(<file)" to make sure the file open on stdin is a regular file, or to make sure the file has been fully read by the time the command is started (in case that command writes to it for instance) or another redirection is processed (like one that would truncate file as in tr 1 2 <<< "$(<file)" > file).

Note that yash supports the <<< operator (though implements it with a pipe (so not a regular file) instead of a temporary file). but not the $(<file) one. You can use <<<"$(cat < file)" instead there. yash strings are characters only, so the "$(cat < file)" will choke on sequences of bytes that don't form valid characters, while other shells can usually cope OK with them.