В обох
<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 open on /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 видається як використаним, так і закритим?