Unix / Linux 下 nohup 和 & 的區別
聲明:本文首發 簡單教程,網址為 https://www.twle.cn/t/332#reply0
就在剛剛回家的路上,被前同事奪命三連 call 呼喚解決一個問題:為啥放在 crontab 裏的命令放在 Shell 會進入假死狀態?
那我就問了?什麽是假死狀態? 同事說,就是一直不會執行完畢,占著 Shell,不能做其它事情。
多次溝通後,才知道他寫的這個是一個守護進程似的死循環程序,一旦啟動除非發生意外,否則不會自己退出。
那肯定,很顯然,會占著 Shell 啊。
nohup 和 &
我給的最簡單的解決方案,就是按下組合鍵 CTRL+Z
。
其次給的是在執行的命令後添加一個 &
符號。 這個是最簡單的後臺執行模式,而且 &
如果只是告訴它這樣,肯定是會出問題的,你能猜到麽 ?
大家想到的第一個問題,肯定是退出 Shell 進程就會自動關閉。對的,沒錯,同事後來給我的答復是退出了進程還存在...囧,我一時不知道怎麽解釋,山高皇帝遠,又沒法遠程和親自查看。
但是,同事給我的第一個問題是:為啥一直輸出日誌啊?
我才想起來,忘記告訴它要 >/dev/null 2&>1
重定向日誌。
後來又吧啦吧啦告訴它還可以使用 nohup
把要執行的命令扔到後臺。
結果呢? 不說還好,一說人家就開問了,這兩個命令有啥區別啊 ?
啊 ? 區別?
&
和nohup
都能把一個任務放在後臺運行,但&
命令會隨著退出遠程 Shell 而自動停止任務,而nohup
則會一直繼續運行,除非顯示殺掉或者重啟電腦
等等,這就完了?
我心慌了...只好回來繼續查資料了。
Linux 程序生命周期裏最重要的三個信號
來,考考大家,我們平時按的最多的兩個組合鍵 CTRL+C
和 CTRL+Z
分別會產生什麽信號 ?
當我們退出遠程 Shell 時,又會產生什麽信號 ?
可以說,Linux 下有很多信號,但真正常用的且能夠影響一個程序的信號就只有那麽幾個,比如
信號 | 說明 |
---|---|
SIGINT | 發送給前臺進程組中的所有進程。常用於終止正在運行的程序,一般由 CTRL+C |
SIGTSTP | 發送給前臺進程組中的所有進程,常用於掛起並暫停一個進程,一般由 CTRL+Z 組合鍵觸發 |
SIGHUP | 當用戶退出 Shell 時,由該 Shell 開啟的所有進程都會接收到這個信號,默認動作為終止進程 |
雖然 SIGINT 和 SIGHUP 的默認動作都一樣,但人家是兩個不同的信號,一定要牢記,不然等下你會分不清楚 &
和 nohup
的區別的
&
的運行原理
經過上面的解釋,想必你應該也清楚了,給任何命令加上 &
就會讓該命令在後臺執行
比如我們要在當前目錄運行一個 Python3 服務器,命令一般如下
[[email protected] ~]$ python3 -mhttp.server 7777
Serving HTTP on 0.0.0.0 port 7777 (http://0.0.0.0:7777/) ...
這時候會發現,這個命令始終沒有退出,我們沒法繼續在這個 Shell 上做其它事情,怎麽辦呢 ?
一種就是關閉當前 Shell,然後重新開啟一個 Shell 執行相同的命令,並在命令的末尾添加 &
符號
[[email protected] ~]$ python3 -mhttp.server 7777 &
[1] 27203
這時候就會看到,我們的命令並沒有占據 Shell 而是返回了一個進程號 [1] 27203
。[1]
表示任務 ID,而 27203
則表示進程號,我們可以使用 ps aux | grep python
查看下剛剛的命令是否仍在運行
[[email protected] ~]$ 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
命令查看所有後臺任務
[[email protected] ~]$ jobs
[1]+ Running python3 -mhttp.server 7777 &
這時候我們狂按下 CTRL+C
鍵會發現一定作用都沒有,人家還是靜靜的運行著,從某些方面說 CTRL+C
發送的 SIGINT
是發送給所有前臺進程的,後臺運行的收不到也是自然的現象
然後,我們關閉 Shell,並重新打開 Shell,就會發現剛剛運行的後臺任務也關閉了
[[email protected] ~]$ ps aux | grep python
luojianguo 27501 0.0 0.0 4295984 660 s000 U+ 10:11下午 0:00.00 grep python
因此,可以說 &
運行的後臺任務,會接收 SIGHUP
的信號,也就是對 SIGHUP
信號不免疫。
註意,如果你在本地演示,會發現進程還在,因為,本地 Shell 即使全部退出,Shell 會把這些後臺任務交給登陸用戶的 shell 去打理
nohup 並不會把程序放到後臺執行
註意,很多文章都沒有解釋清楚,包括上面我的說法也是錯的
「 nohup 並不會把程序放在後臺運行 」
比如,我們使用下面的命令
[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
除了提示已經把標準輸出和標準錯誤輸出到 nohup.out 文件外,人家還占據著 Shell 呢
如果你這後按下 CTRL+C
鍵就會發現程序立刻就退出了
[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
^C[[email protected] ~]$
使用 ps aux | grep python
就會看到剛剛運行的程序沒了
[[email protected] ~]$ 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
[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
然後按下使用 CTRL+Z
命令先掛起當前 nohup
的命令
[[email protected] ~]$ nohup python3 -mhttp.server 7777
appending output to nohup.out
[1]+ Stopped nohup python3 -mhttp.server 7777
可以看到我們的程序在後臺是暫停的,但沒有退出,如果我們使用 exit
命令,會提示有停止任務
[[email protected] ~]$ exit
logout
There are stopped jobs.
如果在此輸入 exit
就會直接退出 Shell 並且會把所有的已經停止的程序關閉
[[email protected] ~]$ exit
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
[進程已完成]
然後我們重新開啟一個 Shell 並使用 ps aux
命令,就會什麽也看不到
[[email protected] ~]$ ps aux | grep python
luojianguo 28095 0.0 0.0 4295400 936 s000 S+ 10:57下午 0:00.01 grep python
結合 nohup 和 &
如果我們過結合兩者,比如使用下面的命令
[[email protected] ~]$ nohup python3 -mhttp.server 7777 &
[1] 28097
[[email protected] ~]$ appending output to nohup.out
然後我們運行 exit
命令退出當前 Shell
[[email protected] ~]$ appending output to nohup.out
exit
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
打開一個新的 Shell,輸入 ps aux | grep python
,就會發現之前的程序還存在
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
神奇吧
後記
真的很坑,我一直以為這兩個命令都是用來把前臺程序放到後臺的,結果不是
- 只有
&
是把前臺程序放到後臺的 nohup
只是把讓正在運行的程序忽略SIGHUP
信號而已
聲明:本文首發 簡單教程,網址為 https://www.twle.cn/t/332#reply0
Unix / Linux 下 nohup 和 & 的區別