為什麼我的 Python 後台程序在 SSH 會話終止時結束?
我有一個 bash 腳本,它啟動一個 python3 腳本(我們稱之為
startup.sh
),關鍵行:nohup python3 -u <script> &
當我
ssh
直接進入並呼叫此腳本時,python 腳本在我退出後繼續在後台執行。但是,當我執行這個時:ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"
該過程
ssh
在完成執行後立即結束並關閉會話。兩者有什麼區別?
編輯: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 伺服器消息: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
部分,shell 將標準輸出重定向到 /dev/null 基本上丟棄它。>/path/to/file
也將工作。最後一部分
2>&1
是將 STDERR 重定向到 STDOUT。程序有三個標準的輸入和輸出源。如果它是一個互動式程序,標準輸入通常來自鍵盤,或者如果它正在處理另一個程序的輸出,則來自另一個程序。該程序通常列印到標準輸出,有時列印到標準錯誤。這三個文件描述符(您可以將它們視為“數據管道”)通常稱為 STDIN、STDOUT 和 STDERR。
有時他們沒有被命名,他們被編號!它們的內置編號依次為 0、1 和 2。預設情況下,如果您沒有明確命名或排名第一,那麼您正在談論的是 STDOUT。
鑑於這種情況,您可以看到上面的命令將標準輸出重定向到 /dev/null,這是一個您可以轉儲您不想要的任何內容(通常稱為位桶)的地方,然後將標準錯誤重定向到標準輸出(當你這樣做時,你必須在目的地前面放一個 &)。
因此,簡短的解釋是“該命令的所有輸出都應該被推入黑洞。” 這是使程序真正安靜的一種好方法!