<<< text is a redirection, if affects the file descriptors of a command (here 0, but 4<<< text would affect the fd 4 instead).
While <(...) is an expansion/substitution, not a redirection. That expands to a file name. That affects the arguments passed to a command if inserted there.
cat <(echo test)
Runs cat with a file like /dev/fd/12 as argument. And as it happened also with its fd 12 being open on the reading end of a pipe. cat will not read from its fd 12, but when it opens the /dev/fd/12 file, it will get a new fd (maybe 3) that points to the same pipe as fd 12.
Meanwhile echo test is run in background with its fd 1 connected to the writing end of that same pipe, so echo and cat will end up being connected via that pipe (though the establishment of that communication channel is much more convoluted than with echo text | cat).
cat <<< text
Runs cat without argument and with its fd 0 open for reading on a deleted temporary file that contains test\n.
zsh interprets
<<< test
as
$NULLCMD <<< test
($NULLCMD being typically cat) as happens any time you run something with only redirections (except when there's only one < redirection, in which case $READNULLCMD (typically a pager) is used instead)).
In:
<(echo text)
There's no redirection, just one process substitution that expands to one /dev/fd/12 argument. So that's asking the shell to execute that file.
In zsh, there's no real benefit of using:
cat <(echo test)
cat < <(echo test)
over
echo test | cat
You see this construct in other shells like bash in things like:
IFS= read -r var < <(echo text)
but that's because in those shells, echo text | IFS= read -r var would not work because read is run in a child process. That's not the case in zsh.
Process substitution is useful for commands that only accept input via a file name as argument (and not via stdin) of when you need to pass more than one input to a command (there's only one stdin) like in diff <(cmd1) <(cmd2).
One difference in zsh between cmd1 | cmd2 and cmd2 < <(cmd1) is that in the latter, zsh doesn't wait for cmd1. While it does wait for both cmd1 and cmd2 in cmd1 | cmd2 (if only so as to make both exit statues available in $pipestatus. Compare sleep 1 | uname with uname < <(sleep 1).
cmd <<< foo can be useful when cmd needs to be able to seek into it's input (because in zsh, here-strings like here-documents are implemented with temporary files instead of pipes).
<()is a sub-shell being replaced with a string, and is not being attached to stdin of the process, whereas<<<does attach to stdin like<does, but I'm not 100% on this, so an authoritative answer that explains the fundamentals would be beneficial to many I think! – Alex Forbes Aug 09 '19 at 12:36<()is "process substitution",<<<is a herestring. Look up the docs for those and you will see they're quite unrelated. – muru Aug 09 '19 at 12:46