Ubuntu 12.04では、GNU bashバージョン4.2.25(1)-リリース(x86_64-pc-linux-gnu)を使用して次のコマンドを試しました。
$ bash -c 'pstree -s $$'
init───sshd───sshd───sshd───bash───pstree
$ bash -c 'pstree -s $$;echo'
init───sshd───sshd───sshd───bash───bash───pstree
2つ目は私が期待したものです。 1つbash
目はこのコマンドを実行する場所、2つ目はbash
私が起動する場所、bash -c ...
2番目のbashはbashという子プロセスを起動しますpstree
。
しかし、最初の人に何が起こったのか知りたいです。 2番目のプロセスbash
が消えてpstree
元のサブプロセスになるのはなぜですかbash
?以前の質問に対する回答が2番目の質問に適用されないのはなぜですかbash -c ...
?
答え1
私はそれだけだと言うでしょう尾 呼ぶ 最適化しかし、実際には(最後のリンクからわかるように)bash
テール呼び出しは最適化されていません。実行するコマンドが単純なコマンド(つまり、複合コマンドではない場合)の場合にのみ最適化されているように見えますが、リダイレクトがある場合は最適化されません。また、コマンドが and-or リストで最後の場合 (たとえばtrue && true && cmd
or false && true || cmd
) を最適化するように見えますが、trap
s が所定の位置にある場合 (たとえばtrap uname EXIT && cmd
) が正しくないため、最適化されないようです。
2番目のコマンドはコマンドラインの最後のコマンドではないpstree
ため、仕上げ呼び出しではありません。pstree
(テールコールですが、通常はecho
組み込まecho
れているため、とにかく子プロセスは作成されません。)
これらすべてのリンクを読む時間を節約するために(面白いことを望んでいますが)、関数/プログラム/何か他の関数/プログラム/何でも呼び出してすぐに返し、返された値が次の値になることを知っている場合、同じです。関数/プログラム/値を返すすべての項目と呼ばれる場合は、新しいスタックフレームをプッシュして(新しいプロセスの作成)、呼び出しの代わりに現在のスタックフレーム(またはシェルスクリプトの場合はプロセス)を再利用できます。関数(スクリプト実行)を実行して返します。シェルスクリプトではfor lastコマンドを使用して手動でこれを実行できますが、exec
シェルは自動的に実行することもできます。
zsh
どちらもksh
これを行うことができるようですが、次のようになります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
しかし、この観察は私がインストールしたシェルバージョンによる観察だけです。したがって、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)