bashとzshの間のサブシェルと&&のさまざまな動作

bashとzshの間のサブシェルと&&のさまざまな動作

サブシェルでコマンドを実行する方法の理解は、現在シェルが分岐してから、サブシェルが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

おすすめ記事