Em ambos
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
E:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
Todos tee, grepe wcsão iniciados simultaneamente. O que importa então é o que acontece no final.
wcsó imprimirá o resultado quando vir o final do arquivo em sua entrada padrão. No primeiro caso, é quando teesai, porque então teeo fechará fdna outra extremidade do canal que wcestá sendo lido (iniciado pela substituição do processo). Não há garantia de que grepterá lido toda a sua entrada até esse momento, muito menos escrito sua saída (dado que os pipes podem conter uma quantidade bastante grande de dados e que wcprovavelmente será mais rápido que grep)
No segundo caso, wco final do arquivo será exibido quando todos os gravadores do canal de leitura estiverem fechando a extremidade do canal. Nesse caso, porém, existem vários escritores. tee(por meio de seu fd aberto sobre /dev/fd/3e por meio de seu fd 3) e grepque também tem seus fd3 abertos para o tubo wc(embora não esteja fazendo nenhum uso dele, muito menos escreva para ele). O interno {provavelmente causará um processo extra de subshell que também terá um fd3 aberto e aguardará ambos teee grep.
Isso significa que wcsó escreverá seu número de linha após a grepsaída.
Se você tivesse escrito da maneira correta, fechando os fds que não precisavam ser abertos:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Então o pedido não teria sido garantido em shells que otimizam o processo do subshell. No entanto, o único shell que eu sei que é, ksh93mas ksh93usa pares de soquetes para pipes, então /dev/fd/3não funcionará lá no Linux pelo menos.
Para ver quais processos estão em execução, você pode substituir greppor ps:
$ { { <file.txt tee /dev/fd/3 4>&- | ps -H >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
PID TTY TIME CMD
8727 pts/5 00:00:00 bash
8815 pts/5 00:00:00 bash
8817 pts/5 00:00:00 tee
8818 pts/5 00:00:00 ps
8816 pts/5 00:00:00 wc
Com bash, você pode ver esse processo extra de shell e também ver o canal aberto no fd 3 com:
$ (p=$BASHPID; { { <file.txt tee /dev/fd/3 4>&- | lsof -ag "$p" -d3 >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1)
COMMAND PID PGID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 9843 9842 chazelas 3w FIFO 0,8 0t0 153304 pipe
tee 9845 9842 chazelas 3w FIFO 0,8 0t0 153304 pipe
lsof 9846 9842 chazelas 3r DIR 0,3 0 1 /proc
grep LITERAL >&4 3>&- 4>&-significa, o fd 4 parece ser usado e fechado?