En ambos
<file.txt tee >(grep LITERAL) >(wc -l) >/dev/null
Y:
{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1
Todos tee
, grep
y wc
se inician simultáneamente. Lo que importa es lo que sucede al final.
wc
solo imprimirá el resultado cuando vea el final del archivo en su entrada estándar. En el primer caso, es cuando tee
sale, porque luego tee
se cerrará fd
en el otro extremo de la tubería que wc
está leyendo (iniciado por la sustitución del proceso). No hay garantía de que grep
habrá leído toda su entrada para ese momento, y mucho menos escrito su salida (dado que las tuberías pueden contener una gran cantidad de datos y que wc
probablemente sea más rápido que grep
)
En el segundo caso, wc
veremos el final del archivo cuando todos los escritores en la tubería desde la que está leyendo hayan cerrado su extremo de la tubería. En ese caso, sin embargo, hay varios escritores. tee
(a través de su fd abierto /dev/fd/3
y a través de su fd 3) y grep
que también tiene sus fd
3 abiertos a la tubería wc
(aunque no lo está utilizando, y mucho menos escribirle). El interno {
probablemente causará un proceso de subshell adicional que también tendrá un fd
3 abierto y esperará a ambos tee
y grep
.
Eso significa que wc
solo escribirá su número de línea después de grep
haber salido.
Si lo hubiera escrito de la manera correcta, es al cerrar los archivos que no necesitaban abrirse:
{ { <file.txt tee /dev/fd/3 4>&- |
grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
Entonces el pedido no se habría garantizado en shells que optimizan el proceso de subshell. Sin embargo, el único shell que sé que sí es, ksh93
pero ksh93
usa pares de conectores para tuberías, por /dev/fd/3
lo que no funcionará allí en Linux al menos.
Para ver qué procesos se están ejecutando, puede reemplazar 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
, puede ver ese proceso de shell adicional, y puede ver que también tiene la tubería abierta en 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 que el fd 4 parece ser usado y cerrado?>&4
, abreviatura de1>&4
,grep
fd 1 y 4 apuntan al mismo recurso (el stdout inicial del shell).grep
no necesita tener su fd 4 abierto a nada. No hace nada con él, así que lo4>&-
Para obtener un pedido predecible use
fuente