Las tuberías no requieren que la primera instancia finalice antes de que comience la otra. En realidad, todo lo que realmente está haciendo es redirigir el stdout de la primera instancia al stdin de la segunda, para que puedan ejecutarse simultáneamente (como tienen que hacer para que funcione la bomba tenedor).
Bueno, ¿cuál es exactamente la salida de :
? ¿Qué se pasa al otro :
?
':' no está escribiendo nada a la otra instancia ':', solo está redirigiendo el stdout al stdin de la segunda instancia. Si escribe algo durante su ejecución (que nunca lo hará, ya que no hace nada más que bifurcarse), iría al stdin de la otra instancia.
Ayuda a imaginar stdin y stdout como una pila:
Todo lo que esté escrito en el stdin estará listo para cuando el programa decida leerlo, mientras que el stdout funciona de la misma manera: un montón en el que puedes escribir, para que otros programas puedan leerlo cuando lo deseen.
De esa manera, es fácil imaginar situaciones como una tubería que no tiene comunicación (dos pilas vacías) o escrituras y lecturas no sincronizadas.
¿Cómo se ejecuta exactamente eso dos veces? En mi opinión, no se pasa nada al segundo :
hasta que el primero :
termina su ejecución, que en realidad nunca terminará.
Como solo estamos redirigiendo la entrada y la salida de las instancias, no es necesario que la primera instancia finalice antes de que comience la segunda. En realidad, generalmente se desea que ambos se ejecuten simultáneamente para que el segundo pueda trabajar con los datos que analiza el primero sobre la marcha. Eso es lo que sucede aquí, ambos serán llamados sin necesidad de esperar a que termine el primero. Eso se aplica a todas las líneas de comandos de cadenas de tuberías.
Estoy pensando que la misma lógica se aplica a: () {: |: &} ;: y
:(){ : & };:
Hace el mismo trabajo que
:(){ :|: & };:
El primero no funcionaría, porque a pesar de que se ejecuta de forma recursiva, la función se llama en segundo plano ( : &
). El primero :
no espera hasta que el "hijo" :
regrese antes de terminar, por lo que al final probablemente solo tenga una instancia de :
ejecución. Si usted tuviera :(){ : };:
que funcionaría sin embargo, ya que la primera :
sería esperar a que el "niño":
para volver, lo que esperar a que su propio "niño" :
para volver, y así sucesivamente.
Así es como se verían los diferentes comandos en términos de cuántas instancias se estarían ejecutando:
:(){ : & };:
1 instancia (llamadas :
y salidas) -> 1 instancia (llamadas :
y salidas) -> 1 instancia (llamadas :
y salidas) -> 1 instancia -> ...
:(){ :|: &};:
1 instancia (llama a 2 :
y se cierra) -> 2 instancias (cada una llama a 2 :
y se cierra) -> 4 instancias (cada una llama a 2 :
y se cierra) -> 8 instancias -> ...
:(){ : };:
1 instancia (llama :
y espera a que regrese) -> 2 instancias (el niño llama a otro :
y espera a que regrese) -> 3 instancias (el niño llama a otro :
y espera a que regrese) -> 4 instancias -> ...
:(){ :|: };:
1 instancia (llama a 2 :
's y espera a que regresen) -> 3 instancias (los niños llaman a 2 :
' cada uno y espera que regresen) -> 7 instancias (los niños llaman a 2 :
'' cada uno y espera a que regresen) -> 15 instancias -> ...
Como puede ver, llamar a la función en segundo plano (usando &
) en realidad ralentiza la bomba tenedor, porque la persona que llama se cerrará antes de que regresen las funciones llamadas.
:|:
, el segundo:
no necesita esperar al primero completado.