Linux job control
Linux 系統中有一個 job control 的概念,本文簡單介紹什麼是 job,以及常見的 job control 命令。本文中演示部分使用的環境為 ubuntu 18.04。
程序組(job)
執行一個命令會建立一個或多個程序,這些程序被稱為一個程序組(process group)。程序組中包含一個或多個程序,每個程序都會屬於一個程序組,程序組也叫 job。
每個程序組都有一個領頭程序(process group leader),領頭程序的 PID 就是程序組的 ID(process group ID,PGID),我們可以通過 ps 命令檢視程序的 PGID:
$ ps -o pid,ppid,pgid,comm | cat
紅框中的兩個程序屬於同一程序組(通過管道符連線的程序屬於相同的程序組)。這個程序組中的領頭程序為 16823,因此它的 PID 成了程序組的 PGID。我們可以通過下圖來理解這幾個程序之間的關係:
領頭程序可以先退出,這時程序組依然存在並且 PGID 也不會發生變化。在程序組中的所有程序都退出後,程序組的證明週期結束。
將程序劃分到程序組中的主要原因是可以對它們進行統一的管理,說白了就是同時發訊號給組內的所有程序,這就是我們接下來要介紹的 job 管理。
Job 管理
有了前面 job 的概念(程序組),接下來我們介紹如何管理 job。
jobs 命令
使用 vim 開啟檔案 test.txt,然後按下 ctrl + z,此時 vim 進入了後臺:
輸出的第一列方括號中的數字表示 jobID,第二列 Stopped 表示 job 當前的狀態,第三列則表示該 job 執行的命令。
使用 jobs 命令可以檢視當前會話中的的所有 jobs,此時執行 jobs 命令,輸出的結果和上面一樣:
& 符
在命令的後面加上 & 符號,可以直接讓 job 執行在後臺:
$ sleep 1000 &
sleep 命令的 jobID 為 2,狀態為 Running。
fg 命令
fg 命令是 foreground 的縮寫。命令格式為 fg %n,它把當前或指定 ID 的 job 放到前臺。下面我們操作一次 job 2:
$ fg %2
此時 sleep 命令執行在前臺,通過 ctrl + z 我們可以再次把它送回後臺:
請注意此時 sleep 命令的狀態已經變成了 Stopped。
ctrl + z
嚴格來說 ctrl + z 並不是一個 job 管理命令,它只是向當前程序傳送一個 SIGSTOP 訊號,該訊號使程序進入暫停(stopped)狀態,也就是掛起程序,此狀態下,程序狀態會被系統儲存,此程序會被放置到作業佇列中去,從而讓出終端。使用 ctrl + z 我們可以暫停正在佔用終端的程序而不結束它,然後我們可以使用終端命令來操作此程序。
bg 命令
bg 命令是 background 的縮寫,命令格式為 bg %n,bg 命令和 ctrl + z 配合可以把前臺命令切換到後臺去執行。比如剛才我們通過 ctrl + z 把 sleep 命令切到了後臺,但變成了 Stopped 狀態,此時執行 bg %2 命令可以讓 sleep 命令繼續在後臺執行:
kill 命令
kill 命令負責向程序傳送訊號,當然它也可以向 job 傳送訊號,在 jobID 前面新增 % 就可以了。比如 SIGCONT 是喚醒一個掛起的程序,所以我們也可以使用下面的命令把處於 Stooped 狀態的 sleep 命令喚醒:
殺死程序
有時候使用 ctrl + c 無法殺死一個正在執行的前臺程序,這是因為 ctrl + c 的本質是向程序傳送 SIGINT 訊號。SIGINT 是用來終止程序的,但是這是一個可以被忽略的訊號,如果程式忽略了它,我們就無法通過 ctrl + c 來終止該程序。
此時我們可以先使用 ctrl + z 把程序切換到後臺,然後使用 kill %n(n 為程序的 jobID)來終止程序。kill 命令預設向程序傳送 SIGTERM 訊號,程式一般會在 SIGTERM 訊號的處理函式中正常地終止程式並執行資源清理工作。既然 SIGTERM 訊號能夠被程式處理,那麼它也能夠被忽略,所以也無法通過這種方式結束那些頑固的程序。
殺死程序的終極手段是 kill -SIGKILL PID(kill -9 PID)。SIGKILL 訊號是不能被忽略的,所以這一招肯定管用。但是由於它過於強硬,使用這種方式殺死程序後往往會有後遺症,比如程序使用的資源沒有在退出前清理乾淨,常見的例子是用這種方法殺死 vim 程序後會遺留下 .swp 檔案。
暫停 tail 命令的輸出
我們一般會使用 tail -f 命令檢視實時的日誌,但很多程式產生日誌的速度非常快以至於我們跟不上節奏。此時使用
ctrl + s 命令可以暫停日誌輸出到終端,這樣我們就可以仔細的分析當前終端中顯示的日誌。如果要接著輸出日誌,可以使用 ctrl + q 命令恢復日誌的輸出。
這兩個命令的原理是:
ctrl + s 會告訴終端暫停,阻塞所有讀寫操作,即不轉發任何資料,只有按了 ctrl + q 後,才會繼續。這個功能應該是歷史遺留的產物,以前終端和伺服器之間沒有流量控制功能,所以有可能伺服器傳送資料過快,導致終端處理不過來,於是需要這樣一個命令告訴伺服器不要再發了,等終端處理完了後再通知伺服器繼續。
參考:
Job Con