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サービスを実行しています。
EDIT2:私も試してみました。初期化スクリプトの生成を呼び出しstartup.sh
て実行しましたが、ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "sudo service start <servicename>"
同じ動作を示しました。
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 Serverメッセージが表示されます。
Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.
SSH経由で手動でログインしてプロセスを直接終了すると、「完了」と表示されます。
EDIT5:EDIT4を使用してエンドポイントに要求するとページが返されますが、Bottleにエラーが発生します。
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です。デフォルトでは、明示的に名前や番号を最初に指定しない場合は、STDOUTについて話します。
この場合、上記のコマンドが標準出力を/ dev / nullにリダイレクトして、不要なエントリ(しばしばビットバケットと呼ばれる)をダンプできる場所で、標準エラーを標準出力にリダイレクトすることがわかります。目的地の前の&)。
したがって、簡単に説明すると、「このコマンドのすべての出力はブラックホールにプッシュする必要があります」です。これはプログラムを本当に静かにする良い方法です!
> /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"
シェルスクリプトstart.shがsshコマンドで実行されます。
説明から:
コマンドを指定すると、ログインシェルではなくリモートホストで実行されます。
これに基づいてスクリプトをリモートで実行する必要があります。
ローカル端末で実行することと異なる点は、nohup python3 -u <script> &
ローカルバックグラウンドプロセスとして実行され、sshコマンドはリモートバックグラウンドプロセスとして実行しようとすることです。
このスクリプトをローカルで実行する場合は、sshコマンドの一部としてstart.shを実行しないでください。次のことを試してみてください。ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> && "./startup.sh"
スクリプトをリモートで実行し、SSHセッションが終了した後にプロセスを続行するには、まずscreen
リモートホストでセッションを開始する必要があります。その後、画面でPythonスクリプトを実行する必要があり、SSHセッションを終了した後も引き続き実行されます。
バラより画面マニュアル
私はscreenが最善の選択だと思いますが、nohupを使用する必要がある場合は、shopt -s huponexit
nohupコマンドを実行する前にリモートホストに設定することを検討してください。または、disown -h [jobID]
プロセスにSIGHUPが送信されないようにマークすることもできます。1
バックグラウンドシェルプロンプトを終了した後にジョブを実行し続けるにはどうすればよいですか?
SIGHUP(hangup)信号は、制御端末または制御プロセスが終了したときにシステムによって使用されます。 SIGHUPを使用して構成ファイルを再ロードし、ログファイルを開いたり閉じたりすることもできます。つまり、端末からログアウトすると、実行中のすべてのジョブが終了します。このような状況を回避するには、-h オプションを disown コマンドに渡すことができます。このオプションは、シェルがSIGHUPを受信したときにSIGHUPがジョブに送信されないように各ジョブIDを表示します。
huponexit
また、シェルがシャットダウン、シャットダウン、または削除されたときにシェルがどのように機能するかについての概要も参照してください。現在の問題は、シェルセッションの終了方法に関連しているようです。2
huponexitオプションが設定されている場合にのみ、SSH接続を介して開かれたシェルのすべての子プロセス(バックグラウンドであるかどうかにかかわらず)は、SSH接続が閉じられるとSIGHUPで終了します。これが本当かどうかを確認するには、shopt huponexitを実行してください。
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
答え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を追加できます(aの後にaを追加するのはエラーです)。disown
nohup
HUP
python
;
&
bash
python3 -u <script> </dev/null &>/dev/null & disown
上記の方法や一部の組み合わせが機能しない場合、問題を解決できる唯一の場所はpython
スクリプト自体です。