Bash

為什麼我的 Python 後台程序在 SSH 會話終止時結束?

  • June 27, 2017

我有一個 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,這是一個您可以轉儲您不想要的任何內容(通常稱為位桶)的地方,然後將標準錯誤重定向到標準輸出(當你這樣做時,你必須在目的地前面放一個 &)。

因此,簡短的解釋是“該命令的所有輸出都應該被推入黑洞。” 這是使程序真正安靜的一種好方法!

> /dev/null 2>&1 是什麼意思?| Xaprb

引用自:https://unix.stackexchange.com/questions/167972