Zarówno
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
I:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
Wszystko tee
, grep
i wc
są uruchamiane jednocześnie. Liczy się to, co stanie się na końcu.
wc
wypisze wynik tylko wtedy, gdy zobaczy koniec pliku na swoim standardowym wejściu. W pierwszym przypadku następuje tee
wyjście, ponieważ wtedy tee
zamknie fd
się na drugim końcu potoku, który wc
czyta (rozpoczęte przez podstawienie procesu). Nie ma gwarancji, że do grep
tego czasu przeczyta wszystkie dane wejściowe, nie mówiąc już o zapisaniu danych wyjściowych (biorąc pod uwagę, że potoki mogą przechowywać dość dużą ilość danych, a to wc
prawdopodobnie będzie szybsze niż grep
)
W drugim przypadku, wc
zobaczysz koniec pliku, gdy wszyscy piszący do potoku, z którego on czyta, zamknęli swój koniec potoku. W takim przypadku jest jednak kilku pisarzy. tee
(przez jego fd otwarty na /dev/fd/3
i przez jego fd 3), grep
który również ma swój fd
3 otwarty na potok do wc
(chociaż nie korzysta z niego, nie mówiąc już o napisaniu do niego). Wewnętrzny {
prawdopodobnie spowoduje dodatkowy proces podpowłoki, który również będzie miał fd
3 otwarte i będzie czekać na oba tee
i grep
.
Oznacza to, że wc
zapisze numer linii dopiero po grep
wyjściu.
Czy napisałeś to we właściwy sposób, to znaczy zamykając fds, które nie wymagały otwarcia:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Wtedy kolejność nie byłaby zagwarantowana w powłokach, które optymalizują proces podpowłoki. Jednak jedyną powłoką, którą znam, jest to, ksh93
że ksh93
korzysta z par gniazd dla potoków, więc /dev/fd/3
nie będzie tam działać przynajmniej w systemie Linux.
Aby zobaczyć, jakie procesy są uruchomione, można wymienić grep
z 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
Za pomocą bash
, możesz zobaczyć ten dodatkowy proces powłoki, i możesz zobaczyć, że ma również otwartą rurkę na fd 3 z:
$ (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>&-
oznacza, że fd 4 wydaje się być używany i zamknięty?>&4
, skrót1>&4
,grep
jest fd 1 i 4 wskazują na ten sam zasób (w powłoce początkowy stdout).grep
nie musi mieć otwartego fd 4 na nic. Nic z tym nie robi, więc zamykamy to4>&-
Aby uzyskać przewidywalne zamówienie, użyj
źródło