В обоих
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
И:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
Все tee, grepи wcзапускаются одновременно. Что имеет значение тогда, это то, что происходит в конце.
wcбудет печатать результат только тогда, когда он видит конец файла на своем стандартном вводе. В первом случае это когда teeвыход, потому что затем teeзакроет его fdна другом конце канала, из которого wcвыполняется чтение (запускается путем подстановки процесса). Нет никакой гарантии, что grepк этому времени будут прочитаны все входные данные, не говоря уже о записанных выходных данных (учитывая, что каналы могут содержать довольно большой объем данных и, wcвероятно, будут быстрее, чем grep)
Во втором случае wcувидит конец файла, когда все записывающие в канал, из которого он читает, закрыли свой конец канала. В этом случае, хотя, есть несколько авторов. tee(через свой открытый fd /dev/fd/3и через свой fd 3) и grepкоторый также имеет свои fd3 открытые для канала wc(хотя он не использует его, не говоря уже о записи в него). Внутренний {, скорее всего, вызовет дополнительный подоболочечный процесс, который также будет иметь fd3 открытых и будет ждать и того, teeи другого grep.
Это означает, что он wcбудет писать свой номер строки только после grepвыхода.
Если бы вы написали это правильно, то есть закрыв fds, который не нужно открывать:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Тогда заказ не будет гарантирован в оболочках, которые оптимизируют процесс подоболочек. Тем не менее, только оболочка , что я знаю , что делает это , ksh93но ksh93использует сокет пар для труб, поэтому /dev/fd/3не будет работать там на Linux , по крайней мере.
Чтобы увидеть, какие процессы запущены, вы можете заменить grepна 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
С помощью bashвы можете увидеть этот дополнительный процесс оболочки, и вы также можете увидеть, что канал открыт на fd 3 с помощью:
$ (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>&-означает, что fd 4, кажется, используется и закрыт?