http app 後來 gts -s 周期 能夠 不同 history

聲明:本文首發 簡單教程,網址為 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+CCTRL+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

神奇吧

後記

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

  1. 只有 & 是把前臺程序放到後臺的
  2. nohup 只是把讓正在運行的程序忽略 SIGHUP 信號而已

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

Unix / Linux 下 nohup 和 & 的區別