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
, grep
e wc
vengono avviate contemporaneamente. Ciò che conta quindi è ciò che accade alla fine.
wc
stamperà il risultato solo quando vede la fine del file sul suo input standard. Nel primo caso, ecco quando tee
esce, perché poi tee
chiuderà la sua fd
sull'altra estremità della pipe da cui wc
sta leggendo (avviata dalla sostituzione del processo). Non vi è alcuna garanzia che grep
avrà 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 wc
probabilmente sarà più veloce di grep
)
Nel secondo caso, wc
vedrà 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/3
e tramite il suo fd 3) e grep
che ha anche il suo fd
3 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 fd
3 aperto e attenderà entrambi tee
e grep
.
Ciò significa che wc
scriverà il suo numero di riga solo dopo grep
essere 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 è ksh93
ma ksh93
usa coppie di socket per pipe, quindi /dev/fd/3
non funzionerà lì almeno su Linux.
Per vedere quali processi sono in esecuzione, è possibile sostituire grep
con 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?