Linux :忘記使用nohup該如何補救
0x00 摘要
在Linux做開發的同學也許會遇到這種困境:
- 運行了一個程序兩個小時之后,你心想:再有一個小時程序就運行完了,於是你興致勃勃的准備看結果。
- 女朋友突然發飆讓自己立刻出現。
- 此時你突然發現自己沒有使用 nohup,這就意味着這個程序在自己離開之后會死掉。之前兩個小時的運行時間就浪費了。
- 於是你滿懷悔恨的按下了CTR+c,然后使用 nohup 重新運行程序。
慢着,其實這種忘記 nohup 的情況是可以補救的,下面我們就看看如何操作。
0x01 問題描述
1.1 為何關閉進程
當用戶注銷(logout)或者網絡斷開時,終端會收到 HUP(hangup)信號從而關閉其所有子進程。
原因是:SSH會話關閉時,ssh所關聯的pty關閉,系統會給這個pty所關聯的session中的所有進程發送SIGHUP信號,SIGHUP的默認信號處理程序是終止進程,除非進程自己處理了SIGHUP。
因此,我們的解決辦法就有兩種途徑:
- 要么讓進程忽略 HUP 信號;
- 要么讓進程運行在新的會話里從而成為不屬於此終端的子進程;
1.2 nohup 作用
nohup
命令對進程做了三件事。
- 阻止
SIGHUP
信號發到這個進程。- 關閉標准輸入。該進程不再能夠接收任何輸入,即使運行在前台。
- 重定向標准輸出和標准錯誤到文件
nohup.out
。
也就是說,nohup
命令實際上將子進程與它所在的 session 分離了。所以當shell窗口關閉時候,nohup 命令所在的進程也不會被結束。
0x02 簡述
如果忘記使用了 nohup,該如何補救?具體操作如下:
2.1 操作序列
具體操作序列如下:
- 對於正在運行的進程,我們可以使用 ”CTRL+ z“ 來將當前進程掛起到后台暫停運行;
- 這時候進程已經進入后台暫停,我們使用 "jobs" 找到之前暫停的進程,每一個后台任務具有一個 jobnumber(任務的序列號,非PID)。
- 使用 "bg jobnumber" 讓該進程進入后台運行;
- 再次使用 "jobs"查看進程狀態,此時進程已經進入running 狀態;
- 使用disown命令 "disown -h %jobnumber" 進行處理,這樣該進程就會起到了 nohup 的同樣作用;此時大功告成。
- 如果想繼續查看,可以使用 ps 命令來查看進程狀態;
- 可以使用 "fg" 把后台任務轉成前台任務運行,此時可以對該進程進行操作,比如結束;
2.2 樣例
我們以運行一個redis為例給出具體操作序列,具體如下圖:
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
mylinux $ jobs
[1]+ Running redis-server &
mylinux $ disown -h %1
mylinux $ ps -elf| grep redis
501 1987 521 4006 0 31 0 4289624 1932 - T 0 ttys001 0:00.01 redis-server *:6 9:49上午
mylinux $ fg
redis-server
^C1987:signal-handler (1616291836) Received SIGINT scheduling shutdown...
1987:M 21 Mar 09:57:16.634 # User requested shutdown...
1987:M 21 Mar 09:57:16.634 * Saving the final RDB snapshot before exiting.
1987:M 21 Mar 09:57:16.641 * DB saved on disk
1987:M 21 Mar 09:57:16.641 # Redis is now ready to exit, bye bye...
0x03 原理
下面我們對操作命令的原理一一進行分析。
3.1 CTRL + Z
Ctrl+Z是把當前的程序掛起,暫停執行這個程序。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
這樣程序就被掛起進入了后台。可以掛起好多進程到后台。
3.2 jobs
jobs命令用來查看當前有多少在后台運行。
在Linux中,啟動、停止、終止以及恢復作業的這些功能統稱為作業控制。作業控制中的關鍵命令是jobs命令,jobs命令允許查看shell當前正在處理的作業。jobs命令中輸出有加號和減號,帶加號的作業被當做默認作業,帶減號的為下一個默認作業。
一旦當前的默認工作處理完成,則帶減號的工作就會自動成為新的默認工作,換句話說,不管此時有多少正在運行的工作,任何時間都會有且僅有一個帶加號的工作和一個帶減號的工作。
我們可以看到,此時 redis-server 就在后台運行,[1] 表示進程編號為 1。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
3.3 bg
bg命令能夠將在后台暫停的命令,變為在后台進行繼續執行。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
使用了bg之后,可以看到輸出 redis-server 之后帶了一個 &,表示已經后台運行。
我們也可以再次使用 jobs 查看進程狀態。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
mylinux $ jobs
[1]+ Running redis-server &
3.4 disown
disown 命令 可以將指定任務從"后台任務"列表(jobs
命令的返回結果)之中移除。一個"后台任務"只要不在這個列表之中,session 就肯定不會向它發出SIGHUP
信號。這樣就達到了 nohup 相同的作用。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
mylinux $ jobs
[1]+ Running redis-server &
mylinux $ disown -h %1
3.5 ps
當使用過 disown 之后,會將把目標作業從作業列表中移除,我們將不能再使用jobs
來查看它,但是依然能夠用ps -ef
查找到它。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
mylinux $ jobs
[1]+ Running redis-server &
mylinux $ disown -h %1
mylinux $ ps -elf| grep redis
501 1987 521 4006 0 31 0 4289624 1932 - T 0 ttys001 0:00.01 redis-server *:6 9:49上午
3.6 fg
fg 命令能夠將在后台運行的命令調至前台進行運行,如果后台運行的任務數量比較多,可以通過選擇jobnumber(任務的序列號,非PID)來進行選擇。
另外關於當前任務,如果后台運行的任務號有2個時候,當1號任務執行完畢之后,2號任務此時就為當前任務,那么使用fg、bg等命令不加上job number的時候,默認為變動的都是當前任務。
mylinux $ redis-server
* The server is now ready to accept connections on port 6379
^Z
[1]+ Stopped redis-server
mylinux $ jobs
[1]+ Stopped redis-server
mylinux $ bg 1
[1]+ redis-server &
mylinux $ jobs
[1]+ Running redis-server &
mylinux $ disown -h %1
mylinux $ ps -elf| grep redis
501 1987 521 4006 0 31 0 4289624 1932 - T 0 ttys001 0:00.01 redis-server *:6 9:49上午
mylinux $ fg
redis-server
0xEE 個人信息
★★★★★★關於生活和技術的思考★★★★★★
微信公眾賬號:羅西的思考
如果您想及時得到個人撰寫文章的消息推送,或者想看看個人推薦的技術資料,敬請關注。
0xFF 參考
https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/
https://www.ibm.com/developerworks/cn/linux/l-cn-screen/
nohup命令_掌握這幾個命令,Linux后台任務提交,前后台任務轉換隨便玩