ああ、それは良いことです。
これはプロセスグループの仕組み、非対話型シェルとして呼び出されたときにbashがどのように動作し、-c
、入力コマンドに&
の効果があるかに関係します。
答えは、UNIXでジョブ制御がどのように機能するかを理解していることを前提としています。すべてのプロセスがプロセスグループに属しています(同じグループのプロセスがコマンドパイプラインの一部として配置されることが多い)。cat(1)
、sort(1)
、およびgrep(1)
のプロセスを実行するのはcat file | sort | grep 'word'
です。同じプロセスグループ)。 bash
は他のプロセスと同様のプロセスであり、プロセスグループにも属します。プロセスグループはセッションの一部です(セッションは1つ以上のプロセスグループで構成されています)。セッションでは、フォアグラウンド・プロセス・グループと呼ばれるプロセス・グループは最大で1つだけであり、多くのバックグラウンド・プロセス・グループが存在します。フォアグラウンドプロセスグループは、端末の制御権を持っています(制御端末がセッションに接続されている場合)。セッションリーダー(bash)は、tcsetpgrp(3)
でプロセスをバックグラウンドからフォアグラウンドに、フォアグラウンドからバックグラウンドに移動します。プロセスグループに送信された信号は、そのグループ内のすべてのプロセスに配信されます。
プロセスグループとジョブコントロールの概念が全く新しい場合は、この回答を完全に理解するためにそれを読んでおく必要があります。これを学ぶには、第9章UNIX環境での高度プログラミング(第3版)があります。
ここで、何が起こっているのか見てみましょう。私たちはパズルのすべての部分を合わせなければなりません。
どちらの場合でも、sshリモート側はbash(1)
を-c
で呼び出します。 -c
フラグは、bash(1)
を非対話型シェルとして実行します。マンページから:
インタラクティブシェル1は、その標準入力と誤差両端子に接続 (isatty(3)により決定される)、またはある-cオプションなしで、非オプションの引数なしで開始し れます1つは-iオプションで を起動しました。bashが 対話型の場合はPS1が設定され、$ - iはシェルスクリプトまたは起動ファイルが の状態をテストできるようにします。
また、bashのは、非対話モードで開始されたときジョブ制御が無効になっていることを知っておくことが重要です。これは、ジョブ制御が無効であるため、このコマンドをフォアグラウンドとバックグラウンドの間で移動する必要はないため、bashはコマンドを実行するために別のプロセスグループを作成しないことを意味します。 。これは、-t
でsshでPTY割り当てを強制したかどうかにかかわらず発生します。
ただし、&
を使用すると、シェルがコマンドの終了を待たないという副作用があります(ジョブ制御が無効になっていても)。 manページから:コマンドが制御演算子&によって終了された場合
、シェル はサブシェルでバックグラウンドでコマンドを実行します。シェルは コマンドが終了するのを待たず、戻りステータスは0です。 コマンドはaで区切られています。順次実行される。各コマンドが終了するまで、シェルは を待ちます。戻りステータスは、最後に実行されたコマンドの終了ステータス( )です。
ので、両方のケースでは、bashはコマンドの実行を待機しません、とtouch(1)
はbash(1)
と同じプロセスグループで実行されます。
ここで、セッションリーダーが終了したときにどうなるかを考えてみましょう。 setpgid(2)
manページから引用:セッションが制御端末を持っており、その 端末に対してCLOCALフラグが設定されていない、と端末ハングアップは、セッション リーダーがSIGHUPを送信し、発生し
場合。 セッションリーダーが終了すると、SIGHUP シグナルも、制御端末のフォアグラウンドプロセス グループの各プロセスに送信されます。
(重点鉱山)
あなたが-t
を使用しない場合は、あなたが-t
を使用していない、リモート側にはPTYの割り当てがないので、bashがない
実際には新しいセッションは作成されません。 sshdはデーモンとして実行されているので、fork + exec()のdashプロセスには制御端末はありません。そのため、bashはセッションリーダーではない(制御端末がない)ため、シェルが非常に早く終了する(おそらくtouch(1)
の前に)、プロセスグループにはSIGHUP
が送信されません。だからすべてが動作します。
あなたはSSHリモート側が、setsid(2)
を呼び出すforkpty(3)
と新しいプロセスをフォーク擬似端子+を割り当て、PTYマスター機器の入力を接続してなることを意味-t
-t
力PTYの割り当てを、使用あなたのマシンにつながるソケットエンドポイントに出力し、最後にbash(1)
を実行します。 forkpty(3)
はbashになるforkedプロセスでPTYスレーブ側を開きます。現在のセッションには制御端末がなく、端末装置が開かれているので、PTY装置はセッションの制御端末になり、bashはセッションのリーダーになります。
同じことが再び起こります。touch(1)
は、同じプロセスグループなどで実行されます。yadda yadda。要は、今度はであり、はであり、セッションリーダーと制御端末である。したがって、bashは&
のために待っているので、終了時にSIGHUP
がプロセスグループに配送され、touch(1)
が早期に死ぬことになります。
についてnohup
nohup(1)
まだ競合状態があるので、ここでは動作しません。 bash(1)
が
をnohup(1)
は、必要な信号処理やファイルのリダイレクトを設定するための機会を得る前に、それは(何が起こるか、おそらくある)は効果がありません
を可能に修正終了した場合は強制的に再有効化ジョブ制御それを修正する。 bashでは、あなたはset -m
でそれを行います。これは動作します:
ssh -t localhost 'set -m ; touch foobar &'
または力bashが完了するのtouch(1)
を待つ:
ssh -t localhost 'touch foobar & wait `pgrep touch`'
私はそれがまさにそれだと思います。バックグラウンドプロセスはttyに接続され、ttyがそれを殺します。 'nohup touch foobar&'を試して、それが動作するかどうか、そして/または 'foobar/dev/null 2>&1'に触れてみてください。 –
'ssh -t localhost 'touch foobar < /dev/null >/dev/null 2>&1&''と 'ssh -t localhost 'nohup touch foobar&' 'はどちらも同じ動作をします。 – user414310
ファイルを作成できませんでしたか?レコードの元のバージョンでもここに作成されたファイルを取得します。 –