にゃおきゃっとさん(@nyaocat])がbashrcの更新に合わせて全bashに反映させたいというツイートをしていたので、

exec bashする方法を提案してみた。

で、結構うまくいくようなので、採用されたみたい。

この点について解説してみる。

exec(2)は現在のプロセスを置き換えるシステムコールで、execコマンドは引数コマンドを現在のプロセス実行し、実行中プロセスと置き換える。

これによって新規bashが起動される。この際

  • PIDは変わらない
  • プロセスの親子関係も変わらない
  • execされた場合、bashはジョブに対してSIGHUPを送らない(子プロセスが終了したりはしない)
  • ジョブテーブルは現行プロセスに固有の情報なので、引き継がれない。バックグラウンドジョブがあった場合、再読み込みされたシェルでjobsしてもリストされない
  • シェル起動後に覚えさせた変数、関数などは引き継がれない。環境変数も消滅する
  • 既に動いている子プロセスに対する影響は全く無い

子プロセスに影響がないのは、親プロセスの変更は子プロセスに伝播しないためだ。 環境変数の変更はあくまでそのプロセスと、そのプロセスから生成されるプロセスに対する影響である。プロセス生成時に引き継がれるだけだからだ。

それどころか、親プロセスが死んで孤児になると、initが引き継ぐが、それでも子プロセスには影響しない。

問題は、積極的にインタラクティブシェルで変数や関数やエイリアスを活用している人は、それらが全てリセットされてしまうことだろう。 あと、ジョブテーブルが消えるのも、ジョブを活用している人には痛い。

.zshrcなら以下で、SIGHUPを送った時に読みなおすようになる。

TRAPHUP() {
  exec zsh -l
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です