誰かが「set -m」の機能を詳細に説明できますか?


16

上のmanページ、それだけで言います:

-mジョブ制御が有効になっています。

しかし、これは実際にはどういう意味ですか?

私はSOの質問でこのコマンドに出くわしました。私はOPと同じ問題を抱えています。これは「ファブリックはTomcatを起動できません」です。そしてset -mこれを解決しました。OPは少し説明しましたが、私にはよくわかりません。

問題はコマンドが終了すると殺されるため、バックグラウンドタスクにありました。

解決策は簡単です。「set -m;」を追加するだけです。コマンドの前のプレフィックス。

回答:


10

bashドキュメントの引用(from man bash):

JOB CONTROL
       Job  control  refers to  the  ability  to selectively  stop
       (suspend) the execution of  processes and continue (resume)
       their execution at a later point.  A user typically employs
       this facility via an interactive interface supplied jointly
       by the operating system kernel's terminal driver and bash.

したがって、非常に簡単に言えば、set -m(インタラクティブシェルのデフォルト)を使用するfgbg、などのビルトインを使用でき、これらはset +m(非インタラクティブシェルのデフォルト)では無効になります。

ただし、ジョブ制御と終了時のバックグラウンドプロセスの終了との関係は明らかではありませんが、1つあることを確認できます:set -m; (sleep 10 ; touch control-on) &コマンドを入力した直後にシェルを終了した場合、実行するとファイルが作成されますが、実行set +m; (sleep 10 ; touch control-off) &されません。

答えは、ドキュメントの残りの部分にあると思いますset -m

-m      Monitor  mode. [...]                     Background pro‐
        cesses run in a separate process group and a  line  con‐
        taining  their exit status is printed upon their comple‐
        tion.

これは、下で開始されたバックグラウンドジョブset +mは実際の「バックグラウンドプロセス」ではないことを意味します(「バックグラウンドプロセスはプロセスグループIDが端末のものと異なる」)。適切なバックグラウンドプロセスのようなプロセスグループ。これは、動作はそのバックグラウンドジョブのいくつかの前にするとき、シェルが終了しますを観察説明:私が正しく理解していれば終了するとき、信号は(これで起動バックグラウンドジョブを殺すシェルと同じプロセスグループ内のプロセスに送信されますset +m)ではなく、他のプロセスグループのものに(したがって、真のバックグラウンドプロセスはそのままで開始されますset -m)。

したがって、あなたの場合、startup.shスクリプトはおそらくバックグラウンドジョブを開始します。リンクした質問のようにSSH経由などでこのスクリプトを非対話的に実行すると、ジョブ制御が無効になり、「バックグラウンド」ジョブはリモートシェルのプロセスグループを共有するため、シェルが終了するとすぐに強制終了されます。逆に、そのシェルでジョブ制御を有効にすると、バックグラウンドジョブは独自のプロセスグループを取得し、その親シェルが終了しても削除されません。


あなたの答えはThxですが、どのようtomcat/bin/startup.shfg/に関連していbgますか?
laike9m

1
直接関係ありません。「ジョブ制御が有効になっている/これは実際にはどういう意味ですか?」と答えようとしていました。一般的な方法で。おそらく明確にしていないかもしれませんが、あなたのスクリプトはバックグラウンドジョブを開始しているように見えます。これが私の答えの残りの部分に当てはまります。
dhag

2

これはgithubの問題リストで見つけましたが、これはあなたの質問に本当に答えていると思います。

これは実際にはSSHの問題ではなく、BASHの非インタラクティブ/インタラクティブモードに関する微妙な動作と、プロセスグループへの信号伝播です。

以下は/programming/14679178/why-does-ssh-wait-for-my-subshel​​ls-without-t-and-kill-them-with-t/14866774#14866774httpに基づいてい ます: //www.itp.uzh.ch/~dpotter/howto/daemonize、いくつかの前提条件は完全に検証されていませんが、これがどのように機能するかについてのテストは確認されているようです。

pty / tty = false

起動されたbashシェルは、開始されたプロセスのstdout / stderr / stdinに接続し、ソケットに何も接続されず、その子が終了するまで実行され続けます。優れたデーモンプロセスは、子プロセスが終了するのを待たずに、子プロセスをフォークしてから終了します。このモードでは、SIGHUPはSSHによって子プロセスに送信されません。これは、自身のデーモン化を処理し、バックグラウンドにする必要のないプロセスを実行するほとんどのスクリプトで正常に機能すると考えています。initスクリプトがプロセスをバックグラウンドするために「&」を使用する場合、主な問題は、セッションが終了した場合にSIGHUPをトリガーするため、バックグラウンドプロセスがstdinからの読み取りを試みるかどうかである可能性があります。

pty / tty = true *

プロセスが開始initスクリプトの背景場合は、親BASHシェルが終了するターン表情で、終了した子プロセスに待機していないだろう、直ちに以来とstdoutでブロックされていない、SSH接続に終了コードを返します。 / stderr / stdin。これにより、SIGHUPが親bashシェルプロセスグループに送信され、bashの非対話モードではジョブ制御が無効になっているため、起動されたばかりの子プロセスが含まれます。デーモンプロセスがフォークまたはフォークされたプロセスで明示的に新しいプロセスセッションを開始する場合、その子プロセスまたはその子プロセスは、終了するBASH親プロセスからSIGHUPを受け取りません。これは、SIGTERMが表示される一時停止ジョブとは異なることに注意してください。この問題は、わずかな競合状態に関係している場合があります。 http://www.itp.uzh.ch/~dpotter/howto/daemonizeを見ると、親セッションが終了する前に実行されない可能性があるフォークされたプロセスによって、新しいセッションが作成されていることがわかります。上記の成功/失敗の動作。スリープ文は、分岐したプロセスが新しいセッションを作成するのに十分な時間を許可します。これが場合によっては機能する理由です。

pty / tty = trueであり、bashでジョブ制御が明示的に有効になっています

SSHは、bashシェルまたは起動された子プロセスのstdout / stderr / stdinに接続しません。つまり、親bashシェルが要求されたコマンドの実行を開始するとすぐに終了します。この場合、ジョブ制御が明示的に有効になっていると、bashシェルによって起動され、それらをバックグラウンドにする '&'を持つプロセスはすぐに別のセッションに配置され、BASHセッションへの親プロセスが終了するときにSIGHUPシグナルを受信しません(この場合のSSH接続)。

修正に必要なもの

バックグラウンドのプロセス/サービスを操作する場合、特別なケースとしてrun / sudo操作のドキュメントでソリューションを明示的に言及するだけでよいと思います。基本的に「pty = false」を使用するか、それが不可能な場合は、最初のコマンドとしてジョブ制御を明示的に有効にすると、動作が正しくなります。

https://github.com/fabric/fabric/issues/395から

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.