我們經常會碰到這樣的問題,想要在linux 服務器運行一些耗時較長的任務, 結果卻由于網絡的不穩定導致任務中途失敗。如何讓命令提交后不受本地關閉終端窗口/網絡斷開連接的干擾呢?
下面列舉了三種方法,可以很方便的滿足上述需求。
問題分析:
我們知道,當用戶注銷(logout)或者網絡斷開時,終端會收到 HUP(hangup)信號從而關閉其所有子進程。因此,我們的解決辦法就有兩種途徑:要么讓進程忽略 HUP 信號,要么讓進程運行在新的會話里從而成為不屬于此終端的子進程。
三種解決辦法:
1. nohup
nohup 無疑是我們首先想到的辦法。顧名思義,nohup 的用途就是讓提交的命令忽略 hangup 信號。
nohup 的使用是十分方便的,只需在要處理的命令前加上 nohup 即可,標準輸出和標準錯誤缺省會被重定向到 nohup.out 文件中。一般我們可在結尾加上”&”來將命令同時放入后臺運行,也可用”>filename 2>&1″來更改缺省的重定向文件名。
nohup 示例
[root@pythontab?~]#?nohup?ping?www.php.cn?& [1]?3059 nohup:?appending?output?to?`nohup.out' [root@pythontab?~]#?ps?-ef?|grep?3059 root??????3059???984??0?15:06?pts/3????00:00:00?ping?www.php.cn root??????3067???984??0?15:06?pts/3????00:00:00?grep?3059 [root@pythontab?~]#
2。setsid
nohup 無疑能通過忽略 HUP 信號來使我們的進程避免中途被中斷,但如果我們換個角度思考,如果我們的進程不屬于接受 HUP 信號的終端的子進程,那么自然也就不會受到 HUP 信號的影響了。setsid 就能幫助我們做到這一點。
setsid 的使用也是非常方便的,也只需在要處理的命令前加上 setsid 即可。
setsid 示例
[root@pythontab?~]#?setsid?ping?www.php.cn [root@pythontab?~]#?ps?-ef?|grep?www.php.cn root?????31094?????1??0?07:28??????????00:00:00?ping?www.php.cn root?????31102?29217??0?07:29?pts/4????00:00:00?grep?www.php.cn [root@pythontab?~]#
值得注意的是,上例中我們的進程 ID(PID)為31094,而它的父 ID(PPID)為1(即為 init 進程 ID),并不是當前終端的進程 ID。
3。& subshell
這里還有一個關于 subshell 的小技巧。我們知道,將一個或多個命名包含在“()”中就能讓這些命令在子 shell 中運行中,從而擴展出很多有趣的功能,我們現在要討論的就是其中之一。
當我們將”&”也放入“()”內之后,我們就會發現所提交的作業并不在作業列表中,也就是說,是無法通過jobs來查看的。讓我們來看看為什么這樣就能躲過 HUP 信號的影響吧。
subshell 示例
[root@pythontab?~]#?(ping?www.php.cn?&) [root@pythontab?~]#?ps?-ef?|grep?www.php.cn root?????16270?????1??0?16:13?pts/4????00:00:00?ping?www.php.cn root?????16278?15362??0?16:13?pts/4????00:00:00?grep?www.php.cn [root@pythontab?~]#
從上例中可以看出,新提交的進程的父 ID(PPID)為1(init 進程的 PID),并不是當前終端的進程 ID。因此并不屬于當前終端的子進程,從而也就不會受到當前終端的 HUP 信號的影響了。
比較而言,我更喜歡用setsid,簡單實用。當然,這里看大家喜好即可,效果上差別不大。