subshellとは何か?分離のための子shell
subshellは、環境の独自のコピーでコマンドのグループを実行する子shell processで、その内部の変更は親に影響しません。
shellは時々、コマンドのグループを分離して実行するために、自身の子コピーであるsubshellを生成します。subshell内での変数の変更やディレクトリの変更は、それが終了すると消えます。これはスコープの制御に役立ちますが、変数がなぜか定着しないときの典型的な混乱の原因でもあります。
subshellとは何か
subshellは、現在のshellからforkされた別のshell processです。親の環境を継承しますが、変数の設定やディレクトリの変更など、それが行う変更はすべてその内部にとどまります。
subshellが作られる方法
- 括弧:
( cd build && make )はsubshellで実行されます。 - pipeline:
|の各側は独自のsubshellで実行されることがあります。 - command substitution:
$(...)はコマンドをsubshellで実行します。
分離の効果
subshellは環境の独自のコピーを持つため、( cd /tmp )は戻った後に親のディレクトリを変更しません。この分離が目的ですが、変更が残ることを期待する人を驚かせます。
よくある落とし穴
pipeされたループ内で設定された変数は、ループがsubshellで実行されたため、残らないことがあります。find . | while read f; do count=$((count+1)); doneは、親でcountを変更しないままにすることがあります。
CIにおけるsubshell
CIスクリプトでは、subshellはサブディレクトリでbuildを実行するなど、外側のshellを汚さずにコマンドをグループ化するのに役立ちます。しかし後でsubshell内で設定された変数に依存すると、それは空になり、見つけにくいバグを引き起こします。
マネージドrunnerでの予測可能なスクリプト
Latchkeyのrunnerでは、ディレクトリ変更のスコープを制限するためにsubshellを使うと、ステップの残りをきれいに保てます。ただし、後で必要になる値はsubshell内で設定するのではなく、親shellにキャプチャする必要があることを忘れないでください。
重要なポイント
- subshellは、環境の分離されたコピーでコマンドを実行する子shellです。
- cdや変数などsubshell内の変更は、親には残りません。
- 括弧、pipeline、
$(...)はすべてスクリプト内でsubshellを作成します。