Unix / Linux 下 nohup 和 & 的區(qū)別

聲明:本文首發(fā) 簡單教程,網址為 https://www.twle.cn/t/332#reply0

就在剛剛回家的路上,被前同事奪命三連 call 呼喚解決一個問題:為啥放在 crontab 里的命令放在 Shell 會進入假死狀態(tài)?

那我就問了?什么是假死狀態(tài)? 同事說,就是一直不會執(zhí)行完畢,占著 Shell,不能做其它事情。

多次溝通后,才知道他寫的這個是一個守護進程似的死循環(huán)程序,一旦啟動除非發(fā)生意外,否則不會自己退出。

那肯定,很顯然,會占著 Shell 啊。

nohup 和 &

我給的最簡單的解決方案,就是按下組合鍵 CTRL+Z

其次給的是在執(zhí)行的命令后添加一個 & 符號。 這個是最簡單的后臺執(zhí)行模式,而且 & 號之前有無空格都沒多大關系,之后有無空格也沒關系。

如果只是告訴它這樣,肯定是會出問題的,你能猜到么 ?

大家想到的第一個問題,肯定是退出 Shell 進程就會自動關閉。對的,沒錯,同事后來給我的答復是退出了進程還存在...囧,我一時不知道怎么解釋,山高皇帝遠,又沒法遠程和親自查看。

但是,同事給我的第一個問題是:為啥一直輸出日志啊?

我才想起來,忘記告訴它要 >/dev/null 2&>1 重定向日志。

后來又吧啦吧啦告訴它還可以使用 nohup 把要執(zhí)行的命令扔到后臺。

結果呢? 不說還好,一說人家就開問了,這兩個命令有啥區(qū)別啊 ?

啊 ? 區(qū)別?

&nohup 都能把一個任務放在后臺運行,但 & 命令會隨著退出遠程 Shell 而自動停止任務,而 nohup 則會一直繼續(xù)運行,除非顯示殺掉或者重啟電腦

等等,這就完了?

我心慌了...只好回來繼續(xù)查資料了。

Linux 程序生命周期里最重要的三個信號

來,考考大家,我們平時按的最多的兩個組合鍵 CTRL+CCTRL+Z 分別會產生什么信號 ?

當我們退出遠程 Shell 時,又會產生什么信號 ?

可以說,Linux 下有很多信號,但真正常用的且能夠影響一個程序的信號就只有那么幾個,比如

|信號|說明|

|:---|:---|

|SIGINT|發(fā)送給前臺進程組中的所有進程。常用于終止正在運行的程序,一般由 CTRL+C 組合鍵觸發(fā)|

|SIGTSTP|發(fā)送給前臺進程組中的所有進程,常用于掛起并暫停一個進程,一般由 CTRL+Z 組合鍵觸發(fā)

|SIGHUP | 當用戶退出 Shell 時,由該 Shell 開啟的所有進程都會接收到這個信號,默認動作為終止進程

雖然 SIGINT 和 SIGHUP 的默認動作都一樣,但人家是兩個不同的信號,一定要牢記,不然等下你會分不清楚 &nohup 的區(qū)別的

& 的運行原理

經過上面的解釋,想必你應該也清楚了,給任何命令加上 & 就會讓該命令在后臺執(zhí)行

比如我們要在當前目錄運行一個 Python3 服務器,命令一般如下


[yufei@www.twle.cn ~]$ python3 -mhttp.server 7777

Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...

這時候會發(fā)現,這個命令始終沒有退出,我們沒法繼續(xù)在這個 Shell 上做其它事情,怎么辦呢 ?

一種就是關閉當前 Shell,然后重新開啟一個 Shell 執(zhí)行相同的命令,并在命令的末尾添加 & 符號


[yufei@www.twle.cn ~]$ python3 -mhttp.server 7777 &

[1] 27203

這時候就會看到,我們的命令并沒有占據 Shell 而是返回了一個進程號 [1] 27203[1] 表示任務 ID,而 27203 則表示進程號,我們可以使用 ps aux | grep python 查看下剛剛的命令是否仍在運行


[yufei@www.twle.cn ~]$ ps aux | grep python

luojianguo      27221  0.0  0.0  4286184    916 s007  S+  10:04下午  0:00.01 grep python

luojianguo      27203  0.0  0.1  4263348  3384 s007  S    9:56下午  0:00.35 /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python -mhttp.server 7777

看到 27203 了沒有,對就是剛剛我們運行的命令。

至于任務 ID [1] ,在 Linux 中,每一個后臺運行的程序,都叫一個任務,當在后臺運行時,會分配一個任務 ID

我們可以使用 jobs 命令查看所有后臺任務


[yufei@www.twle.cn ~]$ jobs

[1]+  Running                python3 -mhttp.server 7777 &

這時候我們狂按下 CTRL+C 鍵會發(fā)現一定作用都沒有,人家還是靜靜的運行著,從某些方面說 CTRL+C 發(fā)送的 SIGINT 是發(fā)送給所有前臺進程的,后臺運行的收不到也是自然的現象

然后,我們關閉 Shell,并重新打開 Shell,就會發(fā)現剛剛運行的后臺任務也關閉了


[yufei@www.twle.cn ~]$ ps aux | grep python

luojianguo      27501  0.0  0.0  4295984    660 s000  U+  10:11下午  0:00.00 grep python

因此,可以說 & 運行的后臺任務,會接收 SIGHUP 的信號,也就是對 SIGHUP 信號不免疫。

注意,如果你在本地演示,會發(fā)現進程還在,因為,本地 Shell 即使全部退出,Shell 會把這些后臺任務交給登陸用戶的 shell 去打理

nohup 并不會把程序放到后臺執(zhí)行

注意,很多文章都沒有解釋清楚,包括上面我的說法也是錯的

「 nohup 并不會把程序放在后臺運行 」

比如,我們使用下面的命令


[yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777

appending output to nohup.out

除了提示已經把標準輸出和標準錯誤輸出到 nohup.out 文件外,人家還占據著 Shell 呢

如果你這后按下 CTRL+C 鍵就會發(fā)現程序立刻就退出了


[yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777

appending output to nohup.out

^C[yufei@www.twle.cn ~]$

使用 ps aux | grep python 就會看到剛剛運行的程序沒了


[yufei@www.twle.cn ~]$ ps aux | grep python

luojianguo      27911  0.0  0.0  4258468    188 s001  U+  10:42下午  0:00.00 grep python

nohup 的真正作用是讓程序忽略 SIGHUP 信號

nohup 命令的作用就是讓程序忽略 SIGHUP 信號,但這里有一個前提,就是進程首先是在后臺運行的,而不是暫停或掛起的

我們演示下一下,使用下面的命令運行一個 nohup


[yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777

appending output to nohup.out

然后按下使用 CTRL+Z 命令先掛起當前 nohup 的命令


[yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777

appending output to nohup.out

[1]+  Stopped                nohup python3 -mhttp.server 7777

可以看到我們的程序在后臺是暫停的,但沒有退出,如果我們使用 exit 命令,會提示有停止任務


[yufei@www.twle.cn ~]$ exit

logout

There are stopped jobs.

如果在此輸入 exit 就會直接退出 Shell 并且會把所有的已經停止的程序關閉


[yufei@www.twle.cn ~]$ exit

logout

Saving session...

...copying shared history...

...saving history...truncating history files...

...completed.

[進程已完成]

然后我們重新開啟一個 Shell 并使用 ps aux 命令,就會什么也看不到


[yufei@www.twle.cn ~]$ ps aux | grep python

luojianguo      28095  0.0  0.0  4295400    936 s000  S+  10:57下午  0:00.01 grep python

結合 nohup 和 &

如果我們過結合兩者,比如使用下面的命令


[yufei@www.twle.cn ~]$ nohup python3 -mhttp.server 7777 &

[1] 28097

[yufei@www.twle.cn ~]$ appending output to nohup.out

然后我們運行 exit 命令退出當前 Shell


[yufei@www.twle.cn ~]$ appending output to nohup.out

exit

logout

Saving session...

...copying shared history...

...saving history...truncating history files...

...completed.

打開一個新的 Shell,輸入 ps aux | grep python,就會發(fā)現之前的程序還存在


luojianguo      28171  0.0  0.0  4295984    668 s000  U+  10:59下午  0:00.00 grep python

luojianguo      28097  0.0  0.3  4271284  12556  ??  S    10:58下午  0:00.26 /usr/local/Cellar/python/3.7.0/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python -mhttp.server 7777

神奇吧

后記

真的很坑,我一直以為這兩個命令都是用來把前臺程序放到后臺的,結果不是

  1. 只有 & 是把前臺程序放到后臺的

  2. nohup 只是把讓正在運行的程序忽略 SIGHUP 信號而已

聲明:本文首發(fā) 簡單教程,網址為 https://www.twle.cn/t/332#reply0

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容