バックグラウンドで起動されたコマンド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 -m
をscript.sh
に入れることです。この場合、最初の場合ではなく、なぜ必要なのですか? script.sh
(したがってcmd
)を実行する2つの方法の間にこの動作の違いがあるのはなぜですか?
最初のケースでは、set -o
をscript.sh
に入れるとわかるように、モニターモードがnotアクティブになっていると思います。
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
_メッセージも無視します(つまり、閉じません)。