La tuyauterie ne nécessite pas que la première instance se termine avant que l'autre ne démarre. En fait, tout ce qu'il fait est de rediriger la sortie standard de la première instance vers la sortie standard de la seconde, afin qu'elles puissent fonctionner simultanément (comme elles doivent le faire pour que la bombe fork fonctionne).
Eh bien, quelle est exactement la sortie de :
? qu'est-ce qui se passe à l'autre :
?
':' n'écrit rien à l'autre ':' instance, il redirige simplement la sortie standard vers la sortie standard de la deuxième instance. S'il écrit quelque chose pendant son exécution (ce qu'il ne fera jamais, puisqu'il ne fait que se bifurquer), il ira au stdin de l'autre instance.
Cela aide à imaginer stdin et stdout comme un tas:
Tout ce qui est écrit dans le stdin sera empilé pour que le programme décide de le lire, tandis que le stdout fonctionne de la même manière: une pile sur laquelle vous pouvez écrire, afin que d'autres programmes puissent le lire quand ils le souhaitent.
De cette façon, il est facile d'imaginer des situations comme un tuyau sans communication (deux piles vides) ou des écritures et des lectures non synchronisées.
Comment est-ce exactement exécuté deux fois? À mon avis, rien n'est transmis au second :
tant que le premier :
n'a pas terminé son exécution, ce qui ne se terminera jamais.
Comme nous redirigeons simplement l'entrée et la sortie des instances, il n'est pas nécessaire que la première instance se termine avant le démarrage de la seconde. Il est généralement souhaitable que les deux s'exécutent simultanément afin que le second puisse fonctionner avec les données analysées par le premier à la volée. C'est ce qui se passe ici, les deux seront appelés sans avoir à attendre la fin du premier. Cela s'applique à toutes les lignes de commandes des chaînes de tuyaux .
Je pense que la même logique s'applique à: () {: |: &} ;: et
:(){ : & };:
Fait le même travail que
:(){ :|: & };:
La première ne fonctionnerait pas, car même si elle s'exécute de manière récursive, la fonction est appelée en arrière-plan ( : &
). Le premier :
n'attend pas que «l'enfant» :
revienne avant de se terminer, donc à la fin vous n'auriez probablement qu'une seule instance d' :
exécution. Si vous l'aviez, :(){ : };:
cela fonctionnerait cependant, car le premier :
attendrait le retour de "l'enfant" :
, qui attendrait le retour de son propre "enfant" :
, etc.
Voici à quoi ressembleraient différentes commandes en termes de nombre d'instances en cours d'exécution:
:(){ : & };:
1 instance (appels :
et sorties) -> 1 instance (appels :
et sorties) -> 1 instance (appels :
et sorties) -> 1 instance -> ...
:(){ :|: &};:
1 instance (appelle 2 :
et quitte) -> 2 instances (chacune appelle 2 :
et quitte) -> 4 instances (chacune appelle 2 :
et quitte) -> 8 instances -> ...
:(){ : };:
1 instance (appelle :
et attend son retour) -> 2 instances (l'enfant appelle une autre :
et attend qu'elle revienne) -> 3 instances (l'enfant appelle une autre :
et attend qu'elle revienne) -> 4 instances -> ...
:(){ :|: };:
1 instance (appelle 2 :
et attend qu'ils reviennent) -> 3 instances (les enfants appellent 2 :
par chacun et attendent qu'ils reviennent) -> 7 instances (les enfants appellent 2 :
par chacun et attendent qu'ils reviennent) -> 15 instances -> ...
Comme vous pouvez le voir, appeler la fonction en arrière-plan (en utilisant &
) ralentit en fait la bombe fourchette, car l'appelé se fermera avant le retour des fonctions appelées.
:|:
, le second:
n'a pas besoin d'attendre que le premier soit terminé.