Python3スクリプト(startup.sh
と呼びましょう)を起動するbashスクリプトがあり、次のキー行があります。
Nohup python3 -u <script> &
ssh
を直接入力してこのスクリプトを呼び出すと、pythonスクリプトは終了後もバックグラウンドで実行され続けます。ただし、これを実行すると、
ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
ssh
が実行を完了してセッションを閉じると、プロセスは終了します。
2つの違いは何ですか?
編集:pythonスクリプトは、Bottleを介してWebサービスを実行しています。
EDIT2:startup.sh
を呼び出してssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "Sudo service start <servicename>"
を実行する initスクリプトの作成 も試しましたが、同じ動作が得られました。
EDIT3:多分それはスクリプトの他の何かです。スクリプトの大部分は次のとおりです。
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"
EDIT4:最後にスリープで最後の行を実行すると:
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)
コマンドを標準の入出力およびエラーフローから切断します。
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の順になっています。デフォルトでは、明示的に名前を付けたり番号を付けたりしない場合は、STDOUTについて話していることになります。
そのコンテキストを考えると、上記のコマンドが標準出力を/ dev/nullにリダイレクトしていることを確認できます。これは、不要なもの(多くの場合、ビットバケットと呼ばれます)をダンプできる場所であり、標準エラーを標準出力にリダイレクトします(これを行うときは、宛先の前に&を付ける必要があります)。
したがって、簡単な説明は「このコマンドからのすべての出力はブラックホールに押し込まれる必要がある」ということです。これは、プログラムを本当に静かにする良い方法の1つです。
>/dev/null 2>&1はどういう意味ですか?| Xaprb
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コマンドを実行する前に、リモートホストでshopt -s huponexit
を設定することを検討してください。または、disown -h [jobID]
を使用してプロセスにマークを付け、SIGHUPがプロセスに送信されないようにすることもできます。 1
バックグラウンドでシェルプロンプトを終了した後、ジョブを実行し続けるにはどうすればよいですか?
SIGHUP(ハングアップ)信号は、システムの制御端末または制御プロセスの終了時に使用されます。 SIGHUPを使用して、設定ファイルをリロードしたり、ログファイルを開いたり閉じたりすることもできます。つまり、ターミナルからログアウトすると、実行中のすべてのジョブが終了します。これを回避するには、-hオプションをdisownコマンドに渡します。このオプションは、シェルがSIGHUPを受信した場合にSIGHUPがジョブに送信されないように、各jobIDをマークします。
また、シェルが終了、強制終了、または削除された場合のhuponexit
の動作の概要もご覧ください。あなたの現在の問題はシェルセッションの終了方法に関連していると思います。 2
Ssh接続を介して開かれたシェルのバックグラウンドの有無にかかわらず、すべての子プロセスは、huponexitオプションが設定されている場合にのみssh接続が閉じられると、SIGHUPで強制終了されます。
Huponexitがtrueの場合、Nohupまたはdisownを使用してプロセスをシェルから切り離すことができるため、終了時にプロセスが強制終了されることはありません。または、画面で物事を実行します。
Huponexitがfalseである場合、これは最近の少なくとも一部のLinuxではデフォルトですが、バックグラウンドジョブは通常のログアウトで強制終了されません。
- ただし、huponexitがfalseの場合でも、ssh接続が強制終了されるか、ドロップすると(通常のログアウトとは異なり)、バックグラウンドプロセスは強制終了されます。これは、(2)のように、disownまたはNohupによって回避できます。
最後に、shopt huponexitの使用例をいくつか示します。
$ 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
競合状態にあると思います。それはこのようなものになるでしょう:
Sshが物事を短くしていなかった場合、次のことが起こりました(これら2つの順序は不明)。
したがって、startup.shとsshは、Nohupが実行する前に終了するため、最後の2つの重要なステップは発生しません。
Startup.shの最後に数秒間スリープすると、問題が解消されると思います。どれだけの時間が必要か正確にはわかりません。それを最小限に抑えることが重要である場合、多分あなたはそれが安全かどうかを確認するためにprocで何かを見ることができます。
たぶん試す価値がある-n
ssh
を開始するときのオプション?これは、ローカルのstdin
へのリモートプロセスの依存関係を防ぎます。もちろん、ssh session
終了します。そして、これにより、stdin
にアクセスしようとすると、リモートの価格が終了します。
これは、python
スクリプトまたはpython
自体の動作に関する問題のように聞こえます。 Nohup
が実際に行うこと(リダイレクトを単純化すること)は、プログラムを実行する前にHUP
シグナルのハンドラーをSIG_IGN
(無視)に設定するだけです。プログラムがSIG_DFL
に戻るように設定したり、実行が開始されたら独自のハンドラーをインストールしたりすることはできません。
コマンドを括弧で囲むと、二重のフォーク効果が得られ、python
スクリプトはシェルプロセスの子ではなくなります。例えば:
( Nohup python3 -u <script> & )
試してみる価値のあるもう1つのこと(別のシェルではなくbash
を使用している場合)は、disown
の代わりにNohup
ビルトインを使用することです。すべてがドキュメントどおりに機能している場合、これは実際には何の違いもありませんが、インタラクティブシェルでは、これによりHUP
信号がpython
スクリプトに伝達されなくなります。次の行または同じ行にdisownを追加できます(;
の後に&
を追加すると、bash
でエラーが発生します)。
python3 -u <script> </dev/null &>/dev/null & disown
上記またはいくつかの組み合わせが機能しない場合、問題を解決する唯一の場所はpython
スクリプト自体にあります。
仕事がセッションに結びついているからだと思います。それが終了すると、すべてのユーザージョブも終了します。
Nohup
がその出力ファイルを開くことができる場合は、Nohup.out
。 python
を介してスクリプトを実行すると、ssh
がパス上にない可能性があります。
コマンドのログファイルを作成してみます。使ってみてください:
Nohup /usr/bin/python3 -u <script> &>logfile &