2

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.

  • 3
    <<< adds a final newline, where as if < file doesn't. $(<...) also removes trailing blank lines, where as < file won't. a better comparison, functionality wise would be <file and < <(cat file) but the former is still more efficient typing wise and implementation wise. – llua Oct 30 '15 at 13:03
  • @llua Your comment should really be an answer. :) – Anthony Geoghegan Oct 30 '15 at 14:48
  • 3
    For a large file, <<<"$(<file)" may be very slow, because the entire file will be read into the shell's memory before it feeds it to the program. – Barmar Oct 30 '15 at 19:34
  • Not wanting to give a history lesson like chazelas is the reason why it is just a comment. – llua Nov 6 '15 at 15:44
4

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.

2

All this commands will write the (txt) (do not try this over binary files) contents of a file:

cat        file
cat       <file
echo   "$(<file)"
cat <<<"$(<file)"

But that is because cat is a very adaptable command, Not because the commands are equal.

  1. The command cat file prints the contents of the file, cat in this case is acting over an actual file. Is similar to less file. But less is much more stringent, it needs an actual file.

  2. The command cat <file is giving the contents of file (already extracted as an stream) to cat, cat is receiving an stream from the standard input. But cat has no trouble with that, it also prints the stream and we see the same result.

  3. In this case echo "$(<file)", the "$(< file)" is exactly equal (except for some sub-shell details) to "$(cat file)". That means that the command cat is executed. Then its output is converted to a text string by the command execution $(...), and, finally, that text string is printed by echo. We see the file contents once again.

  4. The command cat <<<"$(<file)", follows this sequence:

    • "$(<file)" file is read and output as a string

    • the <<< sends the string to the standard input (stdin)

    • and cat prints what it receives in its input (stdin).

We see the same file contents.

Conclusion

We see the same output in all cases. But the contents of the file change in "what they are" (file name, stream, string, etc.) at each part of the commands.

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.