回答:
サブシェルは、元のシェルプロセスとほぼ同一のコピーとして開始されます。内部では、シェルはfork
システムコール1を呼び出し、コードとメモリがコピー2である新しいプロセスを作成します。サブシェルが作成されると、サブシェルとその親の間にはほとんど違いがありません。特に、それらには同じ変数があります。$$
特殊変数でさえ、サブシェルで同じ値を保持します。それは、元のシェルのプロセスIDです。同様$PPID
に、元のシェルの親のPIDもあります。
いくつかのシェルは、サブシェル内のいくつかの変数を変更します。Bash BASHPID
は、シェルプロセスのPIDに設定され、サブシェルで変更されます。Bash、zsh、mksh $RANDOM
は、親とサブシェルで異なる値を生成するように調整します。ただし、これらのような組み込みの特殊なケースを除き、すべての変数は、元のシェルと同じサブシェルの値、同じエクスポートステータス、同じ読み取り専用ステータスなどを持ちます。すべての関数定義、エイリアス定義、シェルオプション、他の設定も継承されます。
によって作成されたサブシェル(…)
は、作成者と同じファイル記述子を持ちます。サブシェルを作成する他の方法は、ユーザーコードを実行する前にいくつかのファイル記述子を変更します。たとえば、パイプの左側はサブシェル3で実行され、標準出力はパイプに接続されています。サブシェルも、いくつかの例外の一つは、サブシェルがカスタムトラップを継承していないということです同じカレントディレクトリ、同じシグナルマスクなどで始まり:無視信号()サブシェルでは無視残るが、他のトラップ(SIGNALは)リセットされデフォルトのアクションに4。trap '' SIGNAL
trap CODE
したがって、サブシェルはスクリプトの実行とは異なります。スクリプトは別のプログラムです。この別のプログラムは、偶然にも親と同じインタープリターによって実行されるスクリプトかもしれませんが、この偶然は別のプログラムに親の内部データの特別な可視性を与えません。エクスポートされない変数は内部データであるため、子シェルスクリプトのインタープリターが実行されると、これらの変数は表示されません。エクスポートされた変数、つまり環境変数は、実行されたプログラムに送信されます。
副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example:
x=1
(echo $x)
1
サブシェルは、それを生成したシェルの複製であるため印刷されます。
x=1
sh -c 'echo $x'
シェルの子プロセスとしてシェルを実行するために起こりますが、x
2行目は、とのこれ以上の接続を持っているx
よりも、2行目を
x=1
perl -le 'print $x'
または
x=1
python -c 'print x'
1 例外は、ksh93
フォークが最適化され、その副作用のほとんどがエミュレートされるシェルです。
2 意味的に、それらはコピーです。実装の観点から見ると、多くの共有が行われています。
3 右側については、シェルに依存します。
4 これをテストする場合、次のようなもの$(trap)
が元のシェルのトラップを報告する可能性があることに注意してください。また、多くのシェルには、トラップが関係するコーナーケースにバグがあることに注意してください。たとえば、ninjaljは、bash 4.3の時点で、「2つのサブシェル」の場合、ネストされたサブシェルからトラップをbash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
実行しますが、中間サブシェルからのトラップではERR
なく、ERR
set -E
ERR
すべてのサブシェルにトラップしますが、中間サブシェルは最適化されて離れているため、ERR
トラップを実行するためにそこにはありません。
echo $(x=2; echo $x)
には、フラグメント$(x=2; echo $x)
を展開する必要があります。これには、コマンドの評価が必要x=2; echo $x
です。の拡張は$x
、この評価中に、パーツを評価した後に発生しx=2
ます。
x
未設定で)echo $(echo foo >somefile)${x-$(cat somefile)}
またはなどの、他の部品に影響を及ぼす副作用がある場合echo $(echo $x),${x=1}
です。
./file
サブシェルでは実行されません。参照してくださいunix.stackexchange.com/q/261638とunix.stackexchange.com/a/157962
明らかに、はい、すべてのドキュメントが言うように、括弧で囲まれたコマンドはサブシェルで実行されます。
サブシェルは、すべての親の変数のコピーを継承します。違いは、サブシェルで行った変更は親でも行われないことです。
kshのmanページは、これをbashのページよりも少し明確にします。
man ksh
:括弧で囲まれたコマンドは、エクスポートされていない変数を削除せずにサブシェルで実行されます。
man bash
:
(
リスト)
listはサブシェル環境で実行されます(以下の「コマンド実行環境」を参照)。シェルの環境に影響を与える変数の割り当てと組み込みコマンドは、コマンドの完了後は有効になりません。
コマンド実行環境
シェルには、次のもので構成される実行環境があります。[...]変数割り当て[...]によって設定されるシェルパラメーター。
コマンド置換、括弧でグループ化されたコマンド、および非同期コマンドは、シェル環境の複製であるサブシェル環境で呼び出されます。[...]
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.
は、次の項目を含む:(· shell variables and functions marked for export, along with variables exported for the command, passed in the environment
同じman bash
セクションから)echo $x
-script x
がエクスポートされない場合に-scriptが何も印刷しない理由を説明します。
x=out; (x=in; echo $x)
)