Uma substituição de comando ( $(...) ) será substituída pela saída do comando, enquanto uma substituição de processo ( <(...) ) será substituída por um nome de arquivo a partir do qual a saída do comando pode ser lida. O comando, em ambos os casos, será executado em um subshell.
No seu caso, a saída de pwd in <(pwd) pode ser encontrada em /dev/fd/63 . Este arquivo deixa de existir assim que o comando que usa a substituição do comando tenha terminado a execução (quando o echo no seu exemplo estiver pronto).
O nome do arquivo retornado por uma substituição de processo é o nome de um descritor de arquivo ou pipe nomeado, não um arquivo regular:
Process substitution is supported on systems that support named pipes (FIFOs) or the
/dev/fdmethod of naming open files.
Um uso comum de substituição de processo é pré-ordenar arquivos para o comando join :
$ join <( sort file1 ) <( sort file2 )
ou para remover colunas de um arquivo (aqui, a coluna 2 é removida de um arquivo delimitado por tabulação usando cut duas vezes e paste para juntar o resultado):
$ paste <( cut -f 1 file ) <( cut -f 3- file )
A substituição de processos é mais ou menos um atalho sintático para evitar o uso explícito de arquivos temporários.
Ambas as substituições de comandos e substituições de processos são executadas em subshells:
$ echo $( t=1234; echo $t )
1234
$ echo $t
(no output)
Aqui, echo obtém 1234 como um argumento de string da substituição de comandos.
$ cat <( t=4321; echo $t )
4321
$ echo $t
(no output)
Aqui, cat obtém o nome do arquivo de um arquivo (named pipe / file descriptor) como seu argumento. O arquivo contém os dados 4321 .