「サブシェル」と「サブプロセス」の正確な違いは何ですか?

「サブシェル」と「サブプロセス」の正確な違いは何ですか?

~によるとこれそしてこれ、サブシェルは括弧で始まります(…)

( echo "Hello" )

~によるとこれこれそしてこれ、コマンドが次に終了すると、プロセスは分岐します。&

echo "Hello" &

Posix仕様の使い方subshellこのページの言葉しかし、定義せずに同じページで「サブプロセス」が定義されていません

どちらもカーネルfork()機能を使用します。そうですか?

一部のフォークを「サブシェル」と呼ぶものと、他のフォークを「サブプロセス」と呼ぶことの正確な違いは何ですか?

ベストアンサー1

POSIX 用語では、サブシェル環境は次の概念に関連付けられています。シェル実行環境

サブシェル環境は、親環境のコピーとして作成された別のシェル実行環境です。実行環境には、オープンファイル、umask、作業ディレクトリ、シェル変数/関数/エイリアスなどが含まれます。

サブシェル環境を変更しても親環境には影響しません。

伝統的に、POSIX仕様の基盤となっているBourneシェルまたはksh88は、子プロセスをフォークしてこれを行います。

POSIXがサブシェル環境でコマンドを実行することを要求または許可する領域は、既存のksh88がサブシェルプロセスを生成する領域です。

ただし、実装がこの目的のために子プロセスを使用することを強制するわけではありません。

シェルは、必要に応じてこの個別の実行環境を実装することを選択できます。

たとえば、ksh93は、親実行環境のプロパティを保存し、ブランチを回避できるコンテキストでサブシェル環境が終了したときにそれを復元します(ほとんどのシステムでは、ブランチはかなり高価であるため最適化)。

たとえば、

cd /foo; pwd
(cd /bar; pwd)
pwd

cd /barPOSIXは別の環境で実行する必要があり、次のように出力されます。

/foo
/bar
/foo

別のプロセスで実行する必要はありません。たとえば、stdout がパイプを壊した場合、サブシェルpwd環境で実行すると、SIGPIPE が唯一のシェルプロセスに転送される可能性が高くなります。

ほとんどのシェルはbash子プロセスのコードを評価してこれを実行しますが(親プロセスが終了するのを待っていますが)、ksh93はすべて同じプロセス内で(...)内部コードを実行しています。(...)

  • サブシェル環境にあることを覚えておいてください。
  • 次に、cd前の作業ディレクトリ(通常はO_CLOEXECで開かれたファイル記述子)を保存し、OLDPWD、PWD変数、および可能なcd修正の値を保存して実行します。chdir("/bar")
  • fchdir()サブシェルから戻った後、現在の作業ディレクトリ(保存されたfdと共に)だけでなく、サブシェルが変更した可能性がある他のすべての項目も復元されます。

場合によっては、サブ処理は避けられない。 ksh93はフォークしません:

  • var=$(subshell)
  • (subshell)

しかしそれは

  • { subshell; } &
  • { subshell; } | other command

つまり、同時に実行するには、ジョブを別のプロセスで実行する必要があります。

ksh93の最適化はそれ以上です。例えば、

var=$(pwd)

ほとんどのシェルはプロセスを分岐し、子プロセスがコマンドを実行し、pwdそのstdoutをパイプにリダイレクトし、現在の作業ディレクトリをそのパイプに書き込み、親プロセスにパイプの反対側で結果を読み取ることができます。を仮想化しますpwdksh93フォークまたはチューブ。フォークとパイプは、組み込まれていないコマンドにのみ使用されます。

サブシェルに加えて、シェルがサブプロセスを生成できる他のコンテキストがあることに注意してください。たとえば、別の実行可能ファイルに格納されているコマンドを実行するには(コマンドは同じシェルソルバーのスクリプトではない)、シェルはコマンドを実行するプロセスを分岐する必要があります。それ以外の場合、コマンドは実行能力を返しません。より多くのコマンド。

存在する:

/bin/echo "$((n += 1))"

これはサブシェルではなく、コマンドは現在のシェル実行環境で評価され、n現在のシェル実行環境の変数は増加しますが、シェルは拡張/bin/echo引数を使用してコマンドを実行するために子プロセスを分岐します$((n += 1))

shell -c 'inline-script'多くのシェルは、外部コマンドがインラインスクリプト()またはサブシェル(サブプロセスとして実装されたサブシェルの場合)の最後のコマンドである場合、外部コマンドを実行するためにサブプロセスを生成しない最適化を実装します。 (bashただし、これはそのコマンドがサブシェルの唯一のコマンドである場合にのみ行われます)。

これは、これらのシェルの場合、サブシェルの最後のコマンドが外部コマンドの場合、サブシェルが追加のプロセスを生成しないことを意味します。比較すると:

a=1; /bin/echo "$a"; a=2; /bin/echo "$a"

そして

a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")

同じ数のプロセスが作成され、2番目の場合にのみ2番目のフォークが早く完了し、サブシェルa=2環境で実行されます。

おすすめ記事