サブシェルを生成するためのBashルールを誤解したようです。私は角括弧が常に独自のプロセスとして実行されるサブシェルを生成すると思いました。
しかし、これは本当ではないようです。コードスニペットA(下)では、2番目のsleep
コマンドは別のシェル(pstree
他の端末によって決定されます)では実行されません。しかし、コードフラグメントBでは、2番目のコマンドsleep
はする別のシェルで実行します。これらのスニペット間の唯一の違いは、2番目のスニペットには角かっこ内に2つのコマンドがあることです。
サブシェルの作成規則を説明できる人はいますか?
コードスニペットA:
sleep 5
(
sleep 5
)
コードピースB:
sleep 5
(
x=1
sleep 5
)
答え1
括弧は常にサブシェルを開始します。何が起こるかは、bashがこれがsleep 5
そのサブシェルによって実行された最後のコマンドであることを検出してexec
代わりに呼び出すことです。fork
+exec
。このsleep
コマンドは、同じプロセス内のサブシェルを置き換えます。
つまり、基本的なケースは次のようになります。
( … )
サブシェルを作成します。元のプロセスはとfork
を呼び出しますwait
。サブプロセスでは、これはサブシェルです。sleep
子プロセスの子プロセスが必要な外部コマンドです。サブシェル呼び出しfork
とwait
。子サブプロセスでは:- 子サブプロセスは外部コマンド→を実行します
exec
。 - 最終コマンドが終了します→
exit
。
- 子サブプロセスは外部コマンド→を実行します
wait
サブシェルで実行されます。
wait
元のプロセスで完了しました。
最適化は次のとおりです。
( … )
サブシェルを作成します。元のプロセスはとfork
を呼び出しますwait
。サブプロセス内では、次を呼び出すまでサブシェルですexec
。sleep
これは外部コマンドであり、プロセスが実行する必要がある最後の操作です。- サブプロセスは外部コマンド→を実行します
exec
。 - 最終コマンドが終了します→
exit
。
wait
元のプロセスで完了しました。
呼び出し後に他のものを追加する場合は、これらのsleep
最適化が発生しないようにサブシェルを保存する必要があります。
呼び出し前に他のものを追加すると最適化が行われますがsleep
(kshはこれを実行します)、bashはそうではありません(この最適化は非常に保守的です)。
答え2
「通常、スクリプトの外部コマンドは子プロセスを分岐しますが、Bashの組み込み機能はそうではありません。したがって、組み込み機能は外部コマンドに対応するコマンドよりも速く実行され、より少ないシステムリソースを使用します。」
もう少し下へ:
「括弧内に含まれるコマンドのリストはサブシェルとして実行されます。」
例:
[root@talara test]# echo $BASHPID
10792
[root@talara test]# (echo $BASHPID)
4087
[root@talara test]# (echo $BASHPID)
4088
[root@talara test]# (echo $BASHPID)
4089
OPコードの使用例
echo $BASHPID
sleep 2
(
echo $BASHPID
sleep 2
echo $BASHPID
)
出力:
[root@talara test]# bash sub_bash
6606
6608
6608
答え3
@Gillesの答えのさらなる説明です。
Gilesが言ったように:The parentheses always start a subshell.
ただし、これらのサブシェルには重複した番号がある可能性があります。
$ (echo "$BASHPID and $$"; sleep 1)
2033 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2040 and 31679
$ (echo "$BASHPID and $$"; sleep 1)
2047 and 31679
ご覧のとおり、$$ は繰り返されます。これは次の理由で予想されます(正しいman bash
行を見つけるにはこのコマンドを実行します)。
$ LESS=+/'^ *BASHPID' man bash
BASHPIDは、
現在のbashプロセスのプロセスIDに展開されます。これは、bashを再初期化する必要がないサブシェルのような場合に応じて$ $とは異なります。
つまり、シェルが再初期化されない場合、$$ は同じです。
または以下を使用してください。
$ LESS=+/'^ *Special Parameters' man bash
特殊パラメータ
$はシェルのプロセスIDに展開されます。 ()サブシェルでは、サブシェルではなく現在のシェルのプロセスIDに展開されます。
$$
現在のシェル(サブシェルではない)のIDです。