In entrambe
<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
Tutti tee, grepe wcvengono avviate contemporaneamente. Ciò che conta quindi è ciò che accade alla fine.
wcstamperà il risultato solo quando vede la fine del file sul suo input standard. Nel primo caso, ecco quando teeesce, perché poi teechiuderà la sua fdsull'altra estremità della pipe da cui wcsta leggendo (avviata dalla sostituzione del processo). Non vi è alcuna garanzia che grepavrà letto tutti i suoi input entro quel momento, figuriamoci scritto i suoi output (dato che le pipe possono contenere una grande quantità di dati e che wcprobabilmente sarà più veloce di grep)
Nel secondo caso, wcvedrà la fine del file quando tutti gli autori della pipe da cui sta leggendo hanno chiuso la loro estremità della pipe. In quel caso, però, ci sono diversi scrittori. tee(tramite il suo fd aperto /dev/fd/3e tramite il suo fd 3) e grepche ha anche il suo fd3 aperto al pipe wc(anche se non lo sta facendo uso, figuriamoci scrivere ad esso). L'interno {probabilmente causerà un ulteriore processo di subshell che avrà anche un fd3 aperto e attenderà entrambi teee grep.
Ciò significa che wcscriverà il suo numero di riga solo dopo grepessere uscito.
Se lo avessi scritto nel modo giusto, cioè chiudendo i fds che non avevano bisogno di essere aperti:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Quindi l'ordine non sarebbe stato garantito nelle shell che ottimizzano il processo di subshell. Tuttavia, l'unica shell che so che fa è ksh93ma ksh93usa coppie di socket per pipe, quindi /dev/fd/3non funzionerà lì almeno su Linux.
Per vedere quali processi sono in esecuzione, è possibile sostituire grepcon 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
Con bash, puoi vedere quel processo extra di shell e puoi vedere che ha anche il pipe aperto su fd 3 con:
$ (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 che fd 4 sembra essere usato e chiuso?