百日半狂乱

Shut the fuck up and write some code!!

指定したプロセスIDのプロセスとその子孫全てを再帰的にkillするシェルスクリプト

二十五日半狂乱、2日目の記事.

実行中のプロセスをkillしたいが、対象のプロセスをkillすると子プロセスがゾンビ化しちゃうからプロセスツリーを丸ごとkillしたくなった.

どうせならkillコマンドっぽくプロセスIDで指定して、指定したプロセスをrootとしてツリーの葉から根に向かってツリー上のプロセスをkillして回りたい.

車輪の再発明の匂いがプンプンするので、「そんなのこうすれば一発じゃん.」ってのがあったらご指摘いただけたらと思います.(※議論し尽くされていました)

追記:後日、↑のリンク先にある"より良いコード"について書いたので、こちらも参考をば.

コードはgithub上に上げた.

doi-t/killpstree

READMEにも書いたけど、目的を達成するシェル関数*1は気持ちいいくらいにシンプル.

killpstree(){
    local children=`ps --ppid $1 --no-heading | awk '{ print $1 }'`
    for child in $children
    do
        killpstree $child
    done
    kill $1
}

プロセスツリーをkill

githubのコードは上記のコード以外は全て動作をテストするためのサンプルなので、実行すると以下のような感じで動作を確認できる.

例えば以下のような子プロセスを5つ持つプロセスを指定すると、

$ pstree -pha 5028
bash,5028 mkpstree.bash
  ├─sleep,5029 12345
  ├─sleep,5030 12345
  ├─sleep,5031 67890
  ├─sleep,5032 67890
  └─sleep,5033 10000

以下のような感じで...

$ bash killpstree.bash "mkpstree.bash" 
=== start:family killing target=[5028] ===
bash,5028 mkpstree.bash
  ├─sleep,5029 12345
  ├─sleep,5030 12345
  ├─sleep,5031 67890
  ├─sleep,5032 67890
  └─sleep,5033 10000
--->>> kill 5029
--->>> kill 5030
--->>> kill 5031
--->>> kill 5032
--->>> kill 5033
--->>> kill 5028

家族皆殺し.

一家の長(pid:5028)は最後にkillされる.

psコマンドのオプション

冒頭のスクリプトでは始めに--ppidオプション*2で子プロセスをシェル変数childrenにリストアップしてしている.

上記のプロセスツリーで言えばこんな感じ.

$ ps --ppid 5028
  PID TTY          TIME CMD
 5029 pts/0    00:00:00 sleep
 5030 pts/0    00:00:00 sleep
 5031 pts/0    00:00:00 sleep
 5032 pts/0    00:00:00 sleep
 5033 pts/0    00:00:00 sleep

ここから左端のプロセスIDだけを抽出している.

日頃からプロセス群と戦っている人にとっては当たり前かもしれないけれど、psコマンドはオプションを工夫すれば実に賢く働いてくれることがわかった.

例えばpsの出力をプロセスツリー状にしたいなら、

$ ps aux --forest
$ ps axjf

出力フォーマットを指定したりもできる.

$ ps -o user,group,pid,ppid,gid,sid  

とまぁこんな具合のサンプルがman psを叩けば冒頭にたくさん出てくるので一度サンプルだけでも目を通しておくと捗るかも.

一応バージョンを明記.

$ ps --version
procps-ng version 3.3.3

sleepのゾンビプロセスだらけになったら

遊んでいると操作に失敗してsleepのゾンビだらけになるので、目障りになったら以下でまとめてkill.

pgrep "sleep" | xargs kill

車輪の再発明

投稿前にそういえば英語で検索してねーなと思って検索したらありました!合掌!

Stack Overflow:Best way to kill all child processes

いろんなやり方があるんだなぁ.

リンク先にはシェルスクリプトだけでなくperlとかpythonでの解法とかもあってより良い情報が得られる.

*1:関数である必然性なんてないんですが.

*2:関係ないけどman psの--ppidの説明文が意味不明過ぎてしばらく硬直してしまった...