Comment bash traite ">> ()"

Tout en expérimentant la redirection de sortie et la substitution de process, je suis tombé sur la command suivante et la sortie qui en résulte:

     moi @ elem: ~ $ echo foo>> (chat);  barre d'écho
     bar
     moi @ elem: ~ $ foo

(Oui, cette nouvelle ligne vide à la fin est intentionnelle.)

Barre de bash echo, imprime mon invite habituelle, echo's foo, echo est une nouvelle ligne, et laisse mon slider. Si j'appuie à nouveau sur Entrée, il imprime mon invite sur une nouvelle ligne et laisse le slider le suivre (comme prévu quand quelqu'un frappe entrer sur une command line vide).

Je m'attendais à écrire foo à un descripteur de file, le chat le lit et écho foo, la deuxième barre d'écho d'écho, puis de nouveau à l'invite de command. Mais ce n'est clairement pas le cas.

Quelqu'un pourrait-il expliquer ce qui se passe?

Vous pouvez voir foo affiché avant la bar , après la bar , ou même après l'invite, en fonction du calendar. Ajoutez un peu de retard pour get un timing cohérent:

 $ echo foo > >(sleep 1; cat); echo bar; sleep 2 bar foo $ 

bar apparaît immédiatement, puis foo après une seconde, puis l'invite suivante après une autre seconde.

Ce qui se passe est que bash exécute les substitutions de process en arrière-plan.

  1. Le process principal bash démarre un sous-shell pour exécuter le sleep 1; cat sleep 1; cat , et met en place un tuyau à lui.
  2. Le process bash principal exécute l' echo foo . Comme cela ne remplit pas le tampon du tube, la command echo termine sans blocage.
  3. Le process principal de bash exécute la echo bar .
  4. Le process principal bash lance la command sleep 2 .
  5. Pendant ce time, le sous-shell lance la command sleep 1 .
  6. Après environ 1 seconde, le sleep 1 revient dans le sous-process. Le sous-process procède à l'exécution de cat .
  7. cat copy son input dans sa sortie (qui est affichée à l'écran) et returnne.
  8. Le sous-shell a fini son travail, il en sort.
  9. Après une autre seconde, le sleep 2 revient. Le process shell principal termine l'exécution et vous obtenez l'invite suivante.

Vous n'avez pas besoin de substitution de process pour get cet effet. Essaye ça:

 ( echo foo | cat & ) 

Vous obtiendrez le même résultat (sans la bar , je laisserai cela comme un exercice) et pour la même raison. Dans les deux cas, le cat est démarré en tâche de fond. Dans ma ligne ici, c'est explicite. Dans le cas de la substitution de process, c'est aussi explicite – c'est un process distinct attaché à un descripteur de file de nom – mais ce n'est peut-être pas aussi évident.

Le process enfant ne se termine pas nécessairement avant bash imprime l'invite suivante. Et puisque sa sortie est mise en memory tampon, elle ne produit rien jusqu'à ce qu'elle se termine. À ce moment, bash vient d'imprimer $ sur stderr, et maintenant le process d'arrière-plan se termine après l'printing de foo et d'une nouvelle ligne.