SLP-KBIT AdventCalendar2023 9日目の記事です
環境
CentOS Linux release 7.9.2009 (Core)
はじめに
リモートのLinuxサーバのファイルの更新を監視したい時がある。
ファイルの変更を監視するシェルスクリプトには以下で紹介されているようなものが有る。
指定したファイルの更新があったらコマンドを自動実行するシェルスクリプト
https://mizti.hatenablog.com/entry/2013/01/27/204343
この例では、while trueの無限ループで監視を行っている。
ローカル環境であれば、無限ループであっても特に問題はない。Ctrl+Cで終了したり、タブを閉じたりすることで、プロセスを停止することができる。
しかし、ssh
コマンドを使ったリモート実行となると話は別だ。
ssh
コマンドは、ssh [USER]@<HOST> [COMMAND]
というように引数に指定したコマンドをサーバ側で実行することができる。
ここに無限ループのシェルスクリプトを記載して実行し、Ctrl+Cで終了しようとすると、
sshは終了するが、サーバ側のシェルスクリプトは動いたままになってしまう(ことがある※)のである。
ssh
する度にサーバ側で無限ループシェルスクリプトのプロセスが増えていくようでは困る。
従って、当記事ではこのプロセスを自動終了する方法について検討する。
プロセス残存問題が生じる条件を検証する
ssh
コマンドで実行した無限ループシェルスクリプトであればSSH接続の切断後もプロセスが残ってしまうと書いたが、実際にはプロセスが残ったり残らなかったりする。この章ではプロセスが残存する条件について様々な検証を踏まえて考察を行う。
(あとで書く)
以上より、
- ttyが無い環境である (
ssh
コマンドの引数指定によるコマンド実行など) - プロセス内でファイルの読み書き(catコマンドやリダイレクトなど)を行っている
という条件下において、親プロセスがなくなったときに子プロセスをinitが回収することで、当該プロセスが残存すると考えられる。
試行錯誤: huponexitの設定を変更する
huponexitをONにすれば、SSHの接続が切れてログアウトした時点でプロセスがkillされるのではないかという案。
シェルスクリプトにshopt -s huponexit
を付け加えてみたが、SSH切断後もプロセスはkillされなかった。
SSH接続の切断を検知するにはどうすればよいか
以下の記事が参考になった。
SSHが切れた時、実行中のプロセスはどうなるか?
https://harasou.jp/2021/07/30/process-on-termainal/
SSH接続が切断されて親プロセスがいなくなると、initが回収してくれるのである。
従って、PPID(親プロセスのプロセスID)の変化を監視することで、SSH接続の切断を検知することができる。
普通、シェルスクリプトからPPIDを取得しようとすれば環境変数$PPID
を参照することを考えるだろう。
しかし、今回の場合、SSH接続の切断によって親プロセスがinitに変わっても、環境変数$PPID
の値は変化しない。
ps
コマンドを使って動的に取得するしか無いと思われる。
ps h -p $$ -o ppid
で自プロセスのPPIDを取得できる。
h
はヘッダを非表示にするオプションである。
-p
はプロセスIDを指定するオプションであり、自プロセスのプロセスIDが格納されている環境変数$$
を指定している。
-o
は表示する項目を指定するオプションであり、ppid
を指定している。
このようにして取得したPPIDが1(init)になったらexitするように実装すれば良い。