Humanity

Edit the world by your favorite way

Ctrl-Cで巻き添えを食らって死なない子を作る

※この記事は多数誤りを含むので参考リンクのみ参考にしてください。

本文

$cmdにエスケープが必要な文字だったり意図しない半角スペースが含まれてる場合は注意。

sh -c "nohup $cmd >/dev/null 2>&1 &"


ただnohup使うってだけの話じゃなくて、
このスクリプトの下の方(アバウト)で
裏でディレクトリを消すプロセスを起動しながら
watchコマンドでディレクトリを表示してどこまで消えたか見せるみたいなスクリプト作ってて必要になった。


普通にnohupコマンドとwatchコマンドのプロセスを同じプロセスグループ内で動かすと
watchコマンドを終了する際のSIGINT(Ctrl-C)がnohupコマンドのプロセスにも送られて死ぬ。
nohupコマンドがトラップ&無視してくれるのはSIGHUPのみなので、
それ以外のSIGINT等のシグナルはトラップされない。
ので、違うプロセスグループで動かすためにデーモンプロセスとして起動(daemonize)する必要があった。

追記:要求満たしてなかったけど嘘は言ってないから(白目)

かかったな、アホが!!! アホは俺でしたすみませんorz


上記に書かれている事は嘘でした。
いや、正確に言うとタイトル通り冒頭で挙げたコマンドは
デーモンプロセスを起動するコマンドですが、今回の要求を満たしていません。
具体的に言うと、よく見たらプロセスが普通にSIGINT受けて死んでました。


何故かというと、上記の説明の内、

違うプロセスグループで動かすためにデーモンプロセスとして起動(daemonize)する必要があった。

ここが嘘で、daemonizeしたとしてもプロセスグループIDは変わりません。
プロセスグループIDが変わるのはsetpgrp(2)が呼び出された場合のみです。多分
setsid(2)で新しいセッションを作成した時もプロセスグループIDが変わります。

なので今回私に必要だったのは「シェルスクリプトでデーモンプロセスを起動する方法」ではなく

  • SIGINTを受けないようプロセスグループIDを変更する
  • ログアウトしても死なないようnohupで起動する

の2点でした。

結論:上記の要求を満たすコマンド

シェルの機能だけではsetpgrp(2)を呼び出すのは無理なので、
今回はperlを使いました。

perl -e "setpgrp; exec @ARGV" -- nohup $cmd >/dev/null 2>&1 &