
startup.sh
キー行を含むpython3 スクリプト ( と呼びます) を起動する bash スクリプトがあります。
nohup python3 -u <script> &
直接ログインしてこのスクリプトを呼び出すとssh
、Python スクリプトは終了後もバックグラウンドで実行され続けます。ただし、これを実行すると:
ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
プロセスはssh
実行が終了し、セッションが閉じられるとすぐに終了します。
この2つの違いは何でしょうか?
編集: Python スクリプトは Bottle 経由で Web サービスを実行しています。
編集2:私も試してみました初期化スクリプトの作成を呼び出しstartup.sh
て実行しましたssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "sudo service start <servicename>"
が、同じ動作になりました。
編集3: おそらくスクリプト内の別の部分でしょう。スクリプトの大部分は次のとおりです:
chmod 700 ${key_loc}
echo "INFO: Syncing files."
rsync -azP -e "ssh -i ${key_loc} -o StrictHostKeyChecking=no" ${source_client_loc} ${remote_user}@${remote_hostname}:${destination_client_loc}
echo "INFO: Running startup script."
ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart"
編集4: 最後の行を最後にスリープさせて実行すると:
ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart; sleep 1"
echo "Finished"
決して到達せずecho "Finished"
、これまで見たことのないボトル サーバー メッセージが表示されます。
Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.
手動で SSH 接続してプロセスを強制終了すると、「完了」と表示されます。
EDIT5: EDIT4 を使用して、任意のエンドポイントにリクエストを送信すると、ページが返されますが、ボトルでエラーが発生します。
Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.
----------------------------------------
Exception happened during processing of request from ('<IP>', 55104)
答え1
コマンドを標準の入力/出力およびエラー フローから切断します。
nohup python3 -u <script> </dev/null >/dev/null 2>&1 &
ssh
これ以上の出力がなく、これ以上の入力を必要としないインジケータが必要です。入力を別のものにして出力をリダイレクトすると、入出力がssh
端末から来たり端末に行ったりしないので、安全に終了できます。つまり、入力はどこか別の場所から来る必要があり、出力 (STDOUT と STDERR の両方) はどこか別の場所に行く必要があります。
部分はの入力として</dev/null
指定します。これがここで役立つ理由は次のとおりです。/dev/null
<script>
/dev/null を stdin にリダイレクトすると、そのプロセスからのすべての読み取り呼び出しに即時 EOF が与えられます。これは通常、プロセスを tty から切り離すのに役立ちます (このようなプロセスはデーモンと呼ばれます)。たとえば、ssh 経由でリモートでバックグラウンド プロセスを開始する場合、プロセスがローカル入力を待機しないように stdin をリダイレクトする必要があります。 https://stackoverflow.com/questions/19955260/what-is-dev-null-in-bash/19955475#19955475
ssh
あるいは、現在のセッションを開いたままにする必要がない限り、別の入力ソースからのリダイレクトは比較的安全です。
部分では、>/dev/null
シェルは標準出力を /dev/null にリダイレクトし、基本的にそれを破棄します。>/path/to/file
も機能します。
最後の部分は2>&1
、STDERR を STDOUT にリダイレクトすることです。
プログラムには、標準的な入力と出力のソースが 3 つあります。対話型プログラムの場合は、標準入力は通常キーボードから、他のプログラムの出力を処理している場合は別のプログラムから取得されます。プログラムは通常、標準出力に出力しますが、標準エラーに出力することもあります。これらの 3 つのファイル記述子 (「データ パイプ」と考えることができます) は、STDIN、STDOUT、STDERR と呼ばれることがよくあります。
名前が付けられず、番号が付けられることもあります。組み込みの番号は、0、1、2 の順です。デフォルトでは、明示的に名前または番号 1 を指定しない場合は、STDOUT について話していることになります。
このコンテキストから、上記のコマンドは標準出力を /dev/null にリダイレクトしていることがわかります。これは、不要なものをダンプできる場所 (ビット バケットと呼ばれることが多い) であり、次に標準エラーを標準出力にリダイレクトします (これを行うときは、宛先の前に & を付ける必要があります)。
したがって、簡単に説明すると、「このコマンドからのすべての出力はブラックホールに押し込まれる必要があります」となります。これは、プログラムを本当に静かにするための 1 つの良い方法です。
> /dev/null 2>&1 はどういう意味ですか? | Xaprb
答え2
見るman ssh
:
ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]
実行すると、ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
シェル スクリプト startup.sh が ssh コマンドとして実行されます。
説明より:
コマンドが指定されている場合は、ログイン シェルではなくリモート ホスト上で実行されます。
これに基づいて、スクリプトをリモートで実行する必要があります。
ローカル ターミナルで実行する場合との違いは、nohup python3 -u <script> &
これはローカル バックグラウンド プロセスとして実行されるのに対し、ssh コマンドはこれをリモート バックグラウンド プロセスとして実行しようとすることです。
スクリプトをローカルで実行する場合は、sshコマンドの一部としてstartup.shを実行しないでください。次のようなコマンドを試してください。ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> && "./startup.sh"
スクリプトをリモートで実行し、SSH セッションが終了した後もこのプロセスを続行したい場合は、まずscreen
リモート ホストでセッションを開始する必要があります。次に、画面内で Python スクリプトを実行する必要があります。これにより、SSH セッションを終了した後もスクリプトが引き続き実行されます。
screen が最良の選択肢だと思いますが、nohup を使用する必要がある場合は、nohup コマンドを実行する前にリモート ホストでの設定を検討してください。または、を使ってプロセスをマークし、そのプロセスに SIGHUP が送信されないようにすることshopt -s huponexit
もできます。disown -h [jobID]
1
バックグラウンドでシェルプロンプトを終了した後もジョブを実行し続けるにはどうすればよいですか?
SIGHUP (ハングアップ) シグナルは、制御端末または制御プロセスの終了時にシステムによって使用されます。SIGHUP を使用して、構成ファイルを再ロードしたり、ログ ファイルを開いたり閉じたりすることもできます。つまり、端末からログアウトすると、実行中のジョブはすべて終了します。これを回避するには、disown コマンドに -h オプションを渡します。このオプションは各ジョブ ID をマークし、シェルが SIGHUP を受信しても SIGHUP がジョブに送信されないようにします。
また、huponexit
シェルが終了、強制終了、またはドロップされたときにどのように動作するかについては、この概要を参照してください。現在の問題は、シェル セッションの終了方法に関連していると思われます。2
ssh 接続を介して開かれたシェルのすべての子プロセス (バックグラウンドであるかどうかに関係なく) は、huponexit オプションが設定されている場合にのみ、ssh 接続が閉じられるときに SIGHUP で強制終了されます。これが当てはまるかどうかを確認するには、shopt huponexit を実行します。
huponexit が true の場合、終了時にプロセスが強制終了されないように、nohup または disown を使用してプロセスをシェルから切り離すことができます。または、screen を使用して実行します。
huponexit が false の場合 (最近の一部の Linux ではこれがデフォルトです)、バックグラウンド ジョブは通常のログアウトでは終了されません。
- しかし、huponexit が false であっても、ssh 接続が強制終了されるか、切断されると (通常のログアウトとは異なります)、バックグラウンド プロセスは強制終了されます。これは、(2) のように disown または nohup によって回避できます。
最後に、shopt huponexit の使用方法の例をいくつか示します。3
$ shopt -s huponexit; shopt | grep huponexit
huponexit on
# Background jobs will be terminated with SIGHUP when shell exits
$ shopt -u huponexit; shopt | grep huponexit
huponexit off
# Background jobs will NOT be terminated with SIGHUP when shell exits
答え3
-n
を起動するときに、オプションを試してみる価値があるかもしれません 。このオプションは、終了するとすぐに閉じられるssh
ローカル へのリモート プロセスの依存関係を防ぎます。また、リモート プロセスがその にアクセスしようとするたびに、その が終了する原因になります。stdin
ssh session
stdin
答え4
python
これは、スクリプトまたはスクリプト自体の動作に問題があるように思われますpython
。実際に行うことはnohup
(リダイレクトを簡素化する以外)、プログラムを実行する前にシグナルのハンドラーを(無視)HUP
に設定することだけです。プログラムが実行を開始したら、それを元に戻したり、独自のハンドラーをインストールしたりすることをSIG_IGN
妨げるものは何もありません。SIG_DFL
試してみるとよいことの 1 つは、コマンドを括弧で囲むことです。これにより、二重フォーク効果が得られ、スクリプトpython
がシェル プロセスの子ではなくなります。例:
( nohup python3 -u <script> & )
試してみる価値があるかもしれないもう 1 つの方法は (bash
別のシェルではなく を使用している場合)、disown
の代わりに組み込みを使用することですnohup
。すべてがドキュメントどおりに動作している場合は、実際に違いは生じませんが、対話型シェルでは、これによりシグナルがスクリプトHUP
に伝播されなくなります。次の行または以下のように同じ行に disown を追加できます (の後に を追加すると でエラーになることにpython
注意してください)。;
&
bash
python3 -u <script> </dev/null &>/dev/null & disown
上記、またはそれらの組み合わせが機能しない場合は、問題に対処できる唯一の場所はpython
スクリプト自体です。