How does the "<( cmd )" pattern work in bash?

This is called process substitution.

3.5.6 Process Substitution

Process substitution allows a process’s input or output to be referred to using a filename.

The process list is run asynchronously, and its input or output appears as a filename. This filename is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list. Note that no space may appear between the < or > and the left parenthesis, otherwise the construct would be interpreted as a redirection. Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files.

It is not just a bash thing as it originally appeared in ksh but it's not in the posix standard.

Under the hood, process substitution has two implementations. On systems which support /dev/fd (most Unix-like systems) it works by calling the pipe() system call, which returns a file descriptor $fd for a new anonymous pipe, then creating the string /dev/fd/$fd, and substitutes that on the command line. On systems without /dev/fd support, it calls mkfifo with a new temporary filename to create a named pipe, and substitutes this filename on the command line.


You can think of <( somecommand ) as the filename of a temporary file containing the output of somecommand. In other words,

utility < <( somecommand )

is a shortcut for

somecommand >tempfile
utility <tempfile
rm -f tempfile

And

utility <( somecommand )

is a shortcut for

somecommand >tempfile
utility tempfile  # notice the lack of redirection here (utility expected to read from "tempfile")
rm -f tempfile

Likewise >( somecommand ) may be thought of as the filename of a temporary file that will be fed into somecommand on its standard input. In other words,

utility > >( somecommand )

is a shortcut for

utility >tempfile
somecommand <tempfile
rm -f tempfile

And

utility >( somecommand )

could possibly be a shortcut for

mkfifo temppipe
somecommand <temppipe &
utility temppipe  # utility is expected to write to "temppipe"
rm -f temppipe

(or something similar)