
¿Sucede algo simbólico al encadenar comandos bash a través de una tubería o es todo computar-pasar-computar-pasar?
Por ejemplo, en head t.txt -n 5 | tail -n 2
, head t.txt -n 5
se calcula y luego tail -n 2
se ejecuta sobre él. ¿O primero hay alguna abstracción para decirle al shell que se deben leer las líneas 3 a 5? Puede que no haga una diferencia en este ejemplo, pero supongo que sí en otros escenarios.
Respuesta1
El shell utiliza la pipe(2)
llamada al sistema para crear un búfer limitado en el kernel con dos descriptores de archivos, uno para permitir que los procesos escriban en el búfer y otro para permitir que los procesos lean desde el búfer.
Consideremos un caso sencillo:
$ p1 | p2
En este caso, conceptualmente, el shell crea la tubería mencionada anteriormente, fork()
s, el hijo conecta su flujo de salida estándar al extremo de escritura de la tubería, luego el hijo exec()
s p1
. A continuación, el shell fork()
s nuevamente, el niño conecta su flujo de entrada estándar al extremo de lectura de la tubería, luego el niño exec()
s p2
. (Yo digoconceptualmenteporque los shells pueden hacer las cosas en diferentes órdenes, pero la idea es la misma).
En ese momento, p1
y p2
se están ejecutando al mismo tiempo. p1
escribirá en la tubería y el núcleo copiará los datos escritos en el búfer. p2
leerá desde la tubería y el kernel copiará los datos leídos del búfer. Si la tubería se llena, entonces el kernel bloqueará p1
su llamada write()
hasta que p2
lea algo de la tubería, liberando algo de espacio. Si la tubería está vacía, entonces el kernel bloqueará p2
su llamada read()
hasta que p1
escriba más datos en la tubería.
Respuesta2
De los dos modelos que sugieres. compute-pass-compute-pass es el más cercano. El shell simplemente conecta los procesos. No sabe nada de lo que están haciendo.
Excepto, El orden de ejecución no está definido. Funcionan efectivamente al mismo tiempo. Sin embargo, el de la izquierda debe generar bytes antes de que el de la derecha los ingrese. Los datos fluyen de izquierda a derecha. Los datos fluyen desde el primer comando, salen de su salida estándar, luego fluyen hacia la entrada estándar, del siguiente proceso, donde se procesan, luego salen de su salida estándar, donde se pueden canalizar a otro proceso, etc. , etcétera etcétera.
Si no hay redirección >
, <
etc. o lectura de un archivo. Entonces se ve así.
┌───────────┐ ┌───────────┐ ┌─────────────┐
Terminal⇨│Process one│⇨│Process two│⇨│Process Three│⇨Terminal
└───────────┘ └───────────┘ └─────────────┘