В обоих
<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
который также имеет свои fd
3 открытые для канала wc
(хотя он не использует его, не говоря уже о записи в него). Внутренний {
, скорее всего, вызовет дополнительный подоболочечный процесс, который также будет иметь fd
3 открытых и будет ждать и того, 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, кажется, используется и закрыт?>&4
, сокращенно1>&4
,grep
fd 1 и 4 указывают на один и тот же ресурс (начальный стандартный вывод оболочки).grep
не нужно, чтобы его fd 4 был открыт для чего-либо. Он ничего с этим не делает, поэтому мы закрываем его4>&-
Для получения предсказуемого заказа используйте
источник