Linux :忘記使用nohup該如何補救

羅西的思考發表於2021-05-31

Linux :忘記使用nohup該如何補救

0x00 摘要

在Linux做開發的同學也許會遇到這種困境:

  1. 執行了一個程式兩個小時之後,你心想:再有一個小時程式就執行完了,於是你興致勃勃的準備看結果。
  2. 女朋友突然發飆讓自己立刻出現。
  3. 此時你突然發現自己沒有使用 nohup,這就意味著這個程式在自己離開之後會死掉。之前兩個小時的執行時間就浪費了。
  4. 於是你滿懷悔恨的按下了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 操作序列

具體操作序列如下:

  1. 對於正在執行的程式,我們可以使用 ”CTRL+ z“ 來將當前程式掛起到後臺暫停執行;
  2. 這時候程式已經進入後臺暫停,我們使用 "jobs" 找到之前暫停的程式,每一個後臺任務具有一個 jobnumber(任務的序列號,非PID)。
  3. 使用 "bg jobnumber" 讓該程式進入後臺執行;
  4. 再次使用 "jobs"檢視程式狀態,此時程式已經進入running 狀態;
  5. 使用disown命令 "disown -h %jobnumber" 進行處理,這樣該程式就會起到了 nohup 的同樣作用;此時大功告成。
  6. 如果想繼續檢視,可以使用 ps 命令來檢視程式狀態;
  7. 可以使用 "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後臺任務提交,前後臺任務轉換隨便玩

Linux的jobs命令

Linux jobs命令:檢視當前終端放入後臺的工作

Linux 守護程式的啟動方法

Linux中shell關閉後,nohup讓程式依然在後臺執行

nohup:關閉shell程式依然執行

相關文章