シェルスクリプトにおいて、バッククォートで括った文字列はサブシェルでコマンドとして実行され、バッククォート文字列はサブシェルの標準出力の内容で置き換えられる。実行するのはあくまでサブシェルなので、バッククォートの中でシェル変数やカレントディレクトリを変更しても、元の親プロセスのシェルは影響を受けない。
% foo=10
% echo `foo=100; echo $foo`
100
% echo $foo
10
そう思っていたら…
% echo $$あれっ? サブシェルのPIDを表示するつもりが、親プロセスのPIDが表示されてしまった。そこで、試しにpsしてみたところ、
69964
% echo `echo $$`
69964
% psサブシェルの子プロセスはどこ?
PID TTY TIME CMD
69964 ttys000 0:00.01 sh
% (ps)
PID TTY TIME CMD
69964 ttys000 0:00.01 sh
ここで、もしかしたらpsしか実行しないサブシェルはforkせずにpsをexecしているかもしれないと思い、psに続けて適当なコマンドをサブシェルで実行してみたところ、
% (ps; echo $foo)ようやくサブシェルが姿を現した。バッククォートを使っても
PID TTY TIME CMD
69964 ttys000 0:00.02 sh
71038 ttys000 0:00.00 sh
10
% echo `ps; echo $foo`ちと見づらいけど、ちゃんとサブシェルのPIDが見える。バッククォートでサブシェルが起動されるという認識は、間違っていなかった模様。
PID TTY TIME CMD 69964 ttys000 0:00.02 sh 71186 ttys000 0:00.00 sh 10
ここで気付いた。親シェルのシェル変数fooがサブシェルに見えているぞ。事前にexportとかしていないので、本来子プロセスには親プロセスのfooは見えないはずだが、バッククォートや()で起動されるサブシェルには、なんらかの方法でシェル変数も引き継がれるのか。そうか、だから$$も親プロセスの値が単純コピーされて、子プロセスで$$を見ても親プロセスと同じだったのだろう。
0 件のコメント:
コメントを投稿