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)