バックグラウンドジョブをスクリプトに入れると、スクリプトとスクリプト呼び出し元が終了した後もジョブが保持されるのはなぜですか?

バックグラウンドジョブをスクリプトに入れると、スクリプトとスクリプト呼び出し元が終了した後もジョブが保持されるのはなぜですか?

lxterminal内で実行される対話型bashシェルでバックグラウンドジョブを実行する場合

$ evince &

その後、シェルを閉じるとバックグラウンドジョブが終了します。

背景コマンドをスクリプトに入れ、対話型bashシェルでスクリプトを実行する場合:

$ cat test.sh 
!# /bin/bash

evince &
$ ./test.sh
$

スクリプトが終了した後も、バックグラウンドジョブはまだ実行中です。対話型bashシェルを終了した後も、バックグラウンドジョブは引き続き実行されます。

バックグラウンドタスクをスクリプトに入れてスクリプトを実行すると、スクリプトの終了とスクリプト呼び出し元の終了の両方でタスクが保持される理由がわかります。タスクをスクリプトにラップすることは、スクリプトが終了し、スクリプトを呼び出すシェルが終了してもタスクを保持するのに最適な方法でしょうか。

ありがとうございます。

答え1

  1. 「シェルを閉じる」とは、ウィンドウを閉じることを意味すると思いますlxterminal 。相互作用lxterminalと相互作用は、カーネルレベルの構成である擬似bashTTYデバイスを介して互いに接続されています。

    bash対話型サブプロセスが継続して実行されている間にこの操作を実行すると、lxterminalプロセスは擬似TTY側を閉じます。これにより、カーネルはSIGHUP信号を相互作用に送信しますbash

    これシグナルこの章では、次のようにman bash述べています。

    デフォルトでは、シェルはSIGHUPを受信した後に終了します。対話型シェルは、シャットダウン前に実行中または停止したすべてのジョブにSIGHUPを再送信します。停止したジョブは、SIGHUPを受信できるようにSIGCONTに送信されます。

    シェルが特定のジョブにシグナルを送信しないようにするには、組み込みdisownコマンド(以下のシェルの組み込みコマンドを参照)を使用してジョブテーブルからそのジョブを削除するか、組み込みコマンドを使用してSIGHUPを受信して​​いないとマークする必要がありますdisown -h

    SIGHUP 信号の予想される意味は、「ユーザー端末への接続が切断されました。必要に応じて、未保存のジョブを保存し、順番に終了します。」です。 (デーモンの場合、これは適用されないため、シグナルは通常、「設定ファイルの再読み込み」および/または「ログの回転のためにログファイルを閉じて再度開く」を意味するために使用されます。)

    マニュアルページに記載されているように、対話はbashSIGHUPシグナルをすべての子に戻します(使用法で特に指定しない限り disown)。これが背景が終了する原因ですevince

  2. しかし、スクリプトを使用するとき、インタラクティブシェルはfork()新しいプロセスでシェルを実行してスクリプトを実行し、スクリプトを実行する新しいシェルがfork()再実行されますevince。その後、スクリプトが終了するため、スクリプトを実行したシェルは終了します。

    この時点で、evinceプロセスには親プロセスはもうありません。ただし、リストを見ると、ps -efPPIDフィールドが空のプロセスは決してありません。プロセスは親プロセスを持つことはできません。。したがって、この状況を処理するために、カーネルはevince孤立プロセスにPPID 1を割り当て、このプロセスの採用されたサブプロセスにしますinit。これで、元の対話は、スクリプトを実行しているインスタンスが実際に別のプロセスを開始したことbashを知りません。この知識は、スクリプトを実行するシェルインスタンスとともに消えます。bash

    したがって、対話はセッションの終わりにSIGHUPを送信する必要があるプロセスがbashあることを全く知りません。evince

    このスクリプトで達成することは、実際に意図的に使用されている技術の基本バージョンです。悪魔 プロセスと呼ばれます。ダブルフォーク。 (デーモン化=これを開始したプロセスやセッションとは完全に独立しています。)

    ご覧のとおり、これは実際にはこのevince プロセスを対話型プロセスとは別に維持するのに十分ですbashが、まだGUIログインセッションの一部として残ります。ただし、デーモン全体が必要な場合は、第2四半期の前にいくつかの追加手順を実行する必要があります。

    • 標準入力、標準出力、標準エラーが次にリダイレクトされることを確認します。/dev/null
    • 別のファイル記述子が開いている場合は閉じます。
    • cd /これにより、プロセスが実際に特定のファイルシステム上のファイルにアクセスする必要がある場合を除き、プロセスはファイルシステムのマウント/マウント解除を誤って妨げません。
    • umask希望/必要な値に明示的に設定
    • setsidコマンドが使用可能な場合は、それを使用して作成されたプロセスをセッションプロセスグループから切断し、完全に独立して作成する必要があります(つまり、evince &スクリプトの最後に代わりに使用できますexec setsid evince)。

    Bash シェルのデーモンの詳細については、こちらをご覧ください。http://blog.n01se.net/blog-n01se-net-p-145.html

答え2

無料プログラムを終了すると、そのプログラムがログアウトプロファイルに存在できることを示します。

バックグラウンドタスクを実行するシェルはすでに完了しており、入力を介して同じ効果を得ることができるので、スクリプトを使用すると効果的です。

( evince & )

これにより、バックグラウンドに表示されたサブシェルが起動してから終了します。 evinceは今デーモンです。

関連情報