はじめに
bashのシェルスクリプトでコマンドを実行する時、以下のような実行パターンがそれぞれどう違うのか気になって調べたので備忘録です。特にプロセスIDやプロセスグループの違いを確認してます。
command setsid command setsid command & exec command exec setsid command
背景
AKSPASSを使って、シェルでsshパスワードログインを自動化する方法を調べていて、以下の記事を読んだ。
expectやsshpassを使わずにシェルでSSHパスワード認証を自動化する #Linux - Qiita
そこでは exec setsid ssh ~~~
のようにしてsshを実行している。
また、以下の記事では、ASKPASS自体がexecute the programしてくれるのでexec不要と説明し、setsid ssh ~~~
としている。
これらを見て、setsidやexecをつけて実行した時やそれを組み合わせた時の挙動が気になったので検証した。コマンドは全てbashのシェルスクリプトで実行している。
各コマンドのざっくりとした動作の違い
chatgptに聞きつつ、動作の違いを整理した。ここでは、プロセスツリー(pid,ppid,pgid)と処理モデル(非同期・同期実行)の観点で整理している。
command
- 通常の方法でコマンドを実行する。
- コマンドはシェルスクリプトの子プロセスとして実行される。
- その子プロセスが完了するまで次の処理は実行されない。(同期実行)
setsid command
- setsidコマンドは、新しいセッションとプロセスグループを作成してから指定されたコマンドを実行する。
- コマンドはシェルスクリプトの子プロセスとして実行されるが、プロセスグループは別物となる。
- 同期実行となり、そのコマンドが終了するまで次の処理には進まない。
setsid command &
- setsid commandをバックグラウンドで実行する。(&はコマンドをバックグラウンドで実行するためのシェルの制御構造)
- コマンドはシェルスクリプトとは別プロセスとして起動する。具体的にはinitプロセス(systemdプロセス)を親プロセスとしたプロセスになる。
- バックグラウンド実行にしているので非同期実行となり、コマンドの終了を待たずに次の処理が実行される。
exec command
exec setsid command
それぞれのコマンド実行時のプロセスのPIDを確認する
実際に確認してみた。
実行するコマンドのみ異なる以下のようなシェルスクリプトを5つ用意する。
#!/bin/bash echo "My PID is $$" echo "My PPID is $PPID" PGID=$(ps -o pgid= -p $$) echo "My PGID is $PGID" echo "sleep 10" sleep 10 # ここだけ可変 echo "done."
これを実行しつつ、sleepしている間に別ターミナルでsleepコマンドのpid,ppid,pgidを取得する。
./command.sh My PID is 19071 My PPID is 17043 My PGID is 19071 sleep 10 done. ps -o pid,ppid,pgid,cmd -p $(pgrep -o -x "sleep") PID PPID PGID CMD 19073 19071 19071 sleep 10
全てのコマンドについてこの方法でシェルスクリプトとコマンドのpidを確認し、関係を整理する。
command
pid | ppid | pgid | |
---|---|---|---|
シェルスクリプト | 3485 | 1287 | 3485 |
コマンド | 3486 | 3485 | 3485 |
setsid command
pid | ppid | pgid | |
---|---|---|---|
シェルスクリプト | 2862 | 1287 | 2862 |
コマンド | 2863 | 2862 | 2863 |
コマンドのppidがシェルスクリプトのpidとなっているのは同じだが、pgidは別となっている。
シェルスクリプトでsetsidをつけて実行した場合、子プロセスにはなるがプロセスグループは別となる。
setsid command &
pid | ppid | pgid | |
---|---|---|---|
シェルスクリプト | 9583 | 1287 | 9583 |
コマンド | 9585 | 1 | 9585 |
コマンドのppidは1となり、pgidもシェルスクリプトとは別となっている。
つまり、別プロセスとして実行されている。
余談
setsid command & とexec setsid commandってほぼ一緒じゃない?
どちらも、親プロセスIDは1となるし、プロセスグループもシェルスクリプトのプロセスとは別物になる。
setsid command &はプロセスを置き換えないのでその後に続く処理があれば、commandの実行を待たずその処理に移るという違いはあるが、
setsid command &の後に何も処理がなければexec setsid commandとほぼ同じ動きになる。
chatgptに聞いても概ね同じ回答だった。置き換えるか明示的に終了するかの違いだと。
まとめ
setsid, execをつけたり、組み合わせた時にコマンドのpid,ppid,pgidがどのように変化するのかを確かめた。
プロセスIDとか気にしないのであれば、同期になるか非同期になるかくらいを気にすれば良さそう。