
サブシェルでコマンドを実行する方法の理解は、現在シェルが分岐してから、サブシェルがfork
必要なexec
コマンドをさらに実行することです。
Bashとzshで次のコマンドを実行すると、奇妙な動作が表示されます。
$ ( sleep 5 && sleep 6 )
走るとき強く打つ:
$ echo $$
6410
$ ( sleep 5 && sleep 6 )
ps
以下を考慮すると:
CMD:sleep 5
PID:6590
生産者PID:6589
その後:
CMD: スリープ 6
PID:6616
生産者PID:6589
これらすべてが私にとって意味があります。両方sleep 5
ともsleep 6
同じ親(おそらくサブシェル)を持ちます。
しかし扱いにくい、次の情報を取得します。
$ echo $$
1987
$ ( sleep 5 && sleep 6 )
ps
以下を考慮すると:
CMD:sleep 5
PID:7576
生産者PID:7575
その後:
CMD: スリープ 6
PID:7575
生産者PID:1987年
sleep 5
実行に使用されたプロセスが元のシェルをsleep 6
親にしているのに対して、実行に使用されたプロセスは元のシェルを親にしてsleep 6
いる理由はわかりません。
答え1
Bashでは、次のようなものを取得できます。
$ echo $$
26328
$ ( /bin/sleep 1234 )
$ ps -o pid,ppid,stat,args -C sleep
PID PPID STAT COMMAND
26473 26328 S+ /bin/sleep 1234
Bashがすることは、サブシェルに対して独自の分岐中にサブシェルから1つのコマンドしか実行できないことを認識してから、最適化として自己実行して追加のsleep
分岐を節約することです。同じことが似たようなことにも効果があるbash -c '/bin/sleep'
Bashはを使用して1つのコマンドに対してのみこれを実行し、( true; /bin/sleep 2345 )
中間シェルプロセスも表示できます。明らかにzshは最適化に対してより積極的で、リストの最後のコマンドフォークをスキップします。
ただし、サブシェルを別のシェル内で実行する必要はありません。プロセス。ただ他の場所で実行されているだけだシェル実行環境からPOSIX シェル言語仕様。環境にはumask
(オペレーティングシステムレベルのプロセス固有の項目)とシェル変数などが含まれているため、分岐を介して別の環境を実装することはシンプル方法。しかし、これは必須ではありません。
たとえば、ksh は他の操作を実行します。この単純なサブシェルには分岐がまったくありません。しかし、それでも動作します。我々が得る値はFOO
シェルから得られる。
$ strace -etrace=clone,fork,vfork -f ksh -c 'FOO=out; ( FOO=in; true ); echo "$FOO"'
out
+++ exited with 0 +++
Bashとzshはそこでフォークされます。 kshもsleep
組み込みで実装されているため、明示的に使用しない限り、そのプロセスを見ることはできません/bin/sleep
。