摘自https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 摘自https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 摘自https://www.ibm.com/developerwor ...
摘自https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/
記錄一下Linux下使命令不受終端斷開的影響,保持在後臺運行的幾個方法及其原理。當用戶註銷logout或者網路中斷時,終端會受到HUP(hangup)信號從而關閉其所有子進程。因為解決方法大體有兩種:要麼讓進程忽略HUP信號,要麼讓進程運行在新的會話里從而成為不屬於此終端下的子進程。
1(本地單元測試通過)nohup命令可以讓要執行的命令忽略HUP信號,再加上&可以保證命令一直在後臺運行。
例:nohup commandXXX > test.log 2>&1 &
命令解析:
- nohup可以讓commandXXX這個命令忽略HUP信號;
- 第一個>代表將命令的標準輸出重定向到指定的地方,這裡是test.log
- 2>&1代表重定向標準錯誤重定向到標準輸出,這裡標準輸出已經被重定向到test.log,所以標準錯誤也會輸出到test.log。這裡引申一下:
Linux中標準輸入即STDIN , 在/dev/stdin ,一般指鍵盤輸入, shell里代號是0;
Linux中標準輸出STDOUT, 在/dev/stdout,一般指終端(terminal), 就是顯示器, shell里代號是1;
Linux中標準錯誤STDERR,在/dev/stderr也是指終端(terminal),不同的是,錯誤信息送到這裡 shell里代號是2
- 最後一個&表示讓命令在後臺運行
- 關閉終端後可以通過ps -ef|grep commandXXX命令查找到後臺進程。
2(本地單元測試通過)setsid命令可以讓進行運行在新的會話下,即不屬於當前終端的子進程。那麼即使當前終端發出了HUP信號,也不會影響該進程。
例:setsid commandXXX
其實通過觀察進程中的父進程號(PPID)發現一些端倪,使用setsid後進行的PPID為1(即為init進程ID),並非當前終端的進程ID。
3(本地單元測試通過)將一個或多個命令用()括起來在shell中運行,所提交的作業並不在作業列表中,即無法通過jobs查看到。新提交的進程的PPID為1。
例:(commandXXX)
4(本地單元測試通過)若未加上述任何處理就執行了命令,如何補救才能讓其不受HUP信息的影響呢?答案是作業調度。對於某個已執行的命令,經過以下幾個步驟可以讓其忽略HUP信號:
- 先使用ctrl+z命令將正在執行的命令變為job作業,;
- 使用jobs可以查看到具體的作業號(jobid);
- 再用bg %jobid命令讓其在後臺運行;
- 最後使用disown -h jobid 即可使該作業忽略HUP信號
5(未安裝此命令,暫未驗證)有大量這種需要穩定的在後臺運行的命令時,如何避免對每條命令都做上述的重覆操作呢?答案是screen。screen提供了ANSI/VT100的終端模擬器,能夠在一個真實終端下運行多個全屏的偽終端。screen具有很多參數,功能強大,在此僅簡要分析一下為什麼使用screen可以避免HUP信號的影響:
- 用screen -dnS session new 建立一個處於斷開模式下的會話(並指定其會話名);
- 用screen -list 列出所有會話;
- 用screen -r session name 重新連接指定會話;
- 用ctrl -a D暫時斷開當前會話;
當我們用-r連接到screen會話時,就進入了一個偽終端,不會再受到HUP信號的影響了。
其他命令:
- pstree -H pid 查看進程號對應的進程命令的樹形結構
- fg %jobid 將某個掛起的進程放回前臺
- bg %jobid 將某個掛起的進程調到後臺繼續運行,這一點在調試代碼時尤其有用,因為將代碼編輯器掛起到後臺再重新返回時,游標定位仍停留到上次掛起時的位置,避免了重新地凝望的麻煩。
- ctrl +c 停止當前命令
- jobs -l 列出所有任務的pid,jobs的狀態可以是running/stopped/terminated,但若任務終止了(kill),shell會從當前列表中刪除任務的進程標識。