web-dev-qa-db-ja.com

バックグラウンドで起動される前にプロセスが強制終了されました

バックグラウンドで起動されたコマンドcmdを含むbashスクリプトscript.shを使用しています。

#!/bin/bash
…
cmd &
…

ターミナルエミュレータを開いてscript.shを実行すると、期待どおり、cmdがバックグラウンドで適切に実行されます。つまり、script.shが終了している間、cmdはPPID1でバックグラウンドで実行され続けます。

しかし、前のものから別のターミナルエミュレーター(たとえばxfce4-terminal)を開いて(または私の実際のユースケースであるデスクトップセッションの開始時に)、script.shを実行すると

xfce4-terminal -H -x script.sh

cmdは正しく実行されなくなりました:script.shの終了により強制終了されます。これを防ぐためにNohupを使用するだけでは不十分です。その後にsleepコマンドを配置する必要があります。そうしないと、script.shの終了によって、cmdが強制終了されてから、分離されます。

cmdをバックグラウンドで適切に実行するために私が見つけた唯一の方法は、set -mscript.shに入れることです。この場合、最初の場合ではなく、なぜ必要なのですか? script.sh(したがってcmd)を実行する2つの方法の間にこの動作の違いがあるのはなぜですか?

最初のケースでは、set -oscript.shに入れるとわかるように、モニターモードがnotアクティブになっていると思います。

5
Glyph

cmdが実行されることになっているプロセスは、fork()exec()の間のSIGHUPシグナルによって強制終了され、Nohupラッパーまたはその他のものは実行される機会がなくなります。何らかの効果があります。 (straceで確認できます)

バックグラウンドコマンドを実行する前に、親シェルでNohupの代わりにSIGHUPを_SIG_IGN_(無視)に設定する必要があります。シグナルハンドラーが「無視」または「デフォルト」に設定されている場合、その処理はfork()およびexec()を介して継承されます。例:

_#! /bin/sh
trap '' HUP    # ignore SIGHUP
xclock &
trap - HUP     # back to default
_

または:

_#! /bin/sh
(trap '' HUP; xclock &)
_

このスクリプトを_xfce4-terminal -H -x script.sh_で実行すると、_xclock &_が終了したときに送信されたSIGHUPによってバックグラウンドコマンド(_script.sh_)が強制終了されません。

セッションリーダー(制御端末を「所有」するプロセス、この場合は_script.sh_)が終了すると、カーネルはそのフォアグラウンドからすべてのプロセスにSIGHUPを送信します。プロセスグループ;ただし、_set -m_はジョブ制御を有効にし、_&_で開始されたコマンドはバックグラウンドプロセスグループに配置され、SIGHUPによって通知されません。

ジョブ制御が有効になっていない場合(非対話型スクリプトのデフォルト)、_&_で開始されたコマンドは、同じフォアグラウンドプロセスグループで実行され、「バックグラウンド」モードは、 リダイレクト _/dev/null_からの入力を偽造し、 無視SIGINTおよびSIGQUITにさせます。

かつてフォアグラウンドジョブとして実行されたが、すでに終了したスクリプトからこの方法で開始されたプロセスは、プロセスグループ(死んだ親から継承された)がターミナルのフォアグラウンドグループではなくなったため、SIGHUPで通知されません。

追記:

「ホールドモード」は、xtermと_xfce4-terminal_(およびおそらく他のvteベースの端末)の間で異なるようです。前者はptyのマスター側を開いたままにしますが、後者は_-e_または_-x_で実行されたプログラムが終了した後にそれを切り離し、スレーブ側への書き込みがEIOで失敗する原因になります。 xtermは、フォアグラウンドプロセスグループのプロセスがまだ実行されている間、_WM_DELETE_WINDOW_メッセージも無視します(つまり、閉じません)。

4
mosvy