Pourquoi le `bash -c somecommand` ne laisse pas parfois un process bash?

Sur Ubuntu 12.04, avec GNU bash, version 4.2.25 (1) -release (x86_64-pc-linux-gnu), j'ai essayé la command suivante:

$ bash -c 'pstree -s $$' init───sshd───sshd───sshd───bash───pstree $ bash -c 'pstree -s $$;echo' init───sshd───sshd───sshd───bash───bash───pstree 

Je pense que le second est comme mon attente: le premier bash est où j'ai exécuté ces commands; le second bash est ce que j'ai commencé avec bash -c ... ; et ensuite le second bash va démarrer un sous-process appelé pstree .

Cependant, je me request ce qui s'est passé avec le premier. Pourquoi le deuxième bash disparu et le pstree est devenu un sous-process du bash origine? Et pourquoi la réponse à la question précédente ne s'applique pas à la deuxième bash -c ... ?

J'aurais dit que c'est simplement Tail Call Optimization , mais en fait (comme le souligne le dernier lien), bash n'optimise pas les callbacks. Il semble seulement optimiser le cas où la command à exécuter est une command simple (c'est-à-dire pas une command composée).

La deuxième command n'est pas un appel de queue de pstree , parce que pstree n'est pas la dernière chose dans la command line. (C'est un appel de queue de l' echo , mais l' echo est généralement embedded, donc aucun sous-process ne sera créé pour cela, quel qu'il soit).

Pour sauver la lecture de tous ces liens (bien que j'espère qu'ils sont intéressants), l'idée est que si vous savez qu'une fonction / programme / qui reviendra immédiatement après avoir appelé une autre fonction / programme / valeur renvoyée par la fonction appelée / program / whatever, vous pouvez aussi bien réutiliser le cadre actuel de la stack (ou le process, dans le cas d'un script shell) au lieu de pousser un nouveau cadre de stack (en créant un nouveau process) fonction (exécution du script), puis de return. Dans un script shell, vous pouvez le faire manuellement en utilisant exec pour la dernière command, mais le shell pourrait le faire automatiquement.

zsh et ksh semblent tous les deux pouvoir le faire, mais pas bash :

 $ zsh -c 'if [[ -n foo ]]; then pstree -s $$; else echo hello; fi' init───lightdm───lightdm───init───konsole───bash───pstree $ ksh -c 'if [[ -n foo ]]; then pstree -s $$; else echo hello; fi' init───lightdm───lightdm───init───konsole───bash───pstree $ bash -c 'if [[ -n foo ]]; then pstree -s $$; else echo hello; fi' init───lightdm───lightdm───init───konsole───bash───bash───pstree 

Mais cette observation n'est qu'une observation, basée sur les versions de ces coquilles que j'ai installées, alors YMMV:

 $ zsh --version zsh 5.0.2 (x86_64-pc-linux-gnu) $ ksh --version version sh (AT&T Research) 93u+ 2012-08-01 $ bash --version GNU bash, version 4.2.45(1)-release (x86_64-pc-linux-gnu)