作業管理
舉例來說,我們在登陸 bash 後, 想要一邊複製檔案、一邊進行資料搜尋、一邊進行編譯,還可以一邊進行 vi 程式撰寫! 當然我們可以重複登陸那六個文字介面的終端機環境中,不過,能不能在一個 bash 內達成? 當然可以啊!就是使用 job control 啦!
進行工作管理的行為中, 其實每個工作都是目前 bash 的子程式,亦即彼此之間是有相關性的。 我們無法以 job control 的方式由 tty1 的環境去管理 tty2 的 bash !
或許你會覺得很奇怪啊,既然我可以在六個終端介面登陸,那何必使用 job control 呢? 真是脫褲子放屁,多此一舉啊!不要忘記了呢,我們可以在 /etc/security/limits.conf 裡面配置使用者同時可以登陸的連線數,在這樣的情況下,某些使用者可能僅能以一個連線來工作呢! 所以羅,你就得要瞭解一下這種工作管理的模式了!
由於假設我們只有一個終端介面,因此在可以出現提示位元組讓你操作的環境就稱為前景 (foreground),至於其他工作就可以讓你放入背景 (background) 去暫停或運行。要注意的是,放入背景的工作想要運行時, 他必須不能夠與使用者互動。舉例來說, vim 絕對不可能在背景裡面運行 (running) 的!因為你沒有輸入資料他就不會跑啊! 而且放入背景的工作是不可以使用 [ctrl]+c 來終止的』!
總之,要進行 bash 的 job control 必須要注意到的限制是:
- 這些工作所觸發的程式必須來自於你 shell 的子程式(只管理自己的 bash);
- 前景:你可以控制與下達命令的這個環境稱為前景的工作 (foreground);
- 背景:可以自行啟動並執行工作,你無法使用 [ctrl]+c 終止他,可使用 bg/fg 呼叫該工作;
- 背景中『運行』的程式不能等待 terminal/shell 的輸入(input)
直接將命令丟到背景中『運行』的 &
如同前面提到的,我們在只有一個 bash 的環境下,如果想要同時進行多個工作, 那麼可以將某些工作直接丟到背景環境當中,讓我們可以繼續操作前景的工作!那麼如何將工作丟到背景中? 最簡單的方法就是利用『 & 』這個玩意兒了!舉個簡單的例子,我們要將 /etc/ 整個備份成為 /tmp/etc.tar.gz 且不想要等待,那麼可以這樣做:
[root@www ~]# tar -zpcf /tmp/etc.tar.gz /etc &[1] 8400 <== [job number] PID [root@www ~]# tar: Removing leading `/' from member names # 在中括弧內的號碼為工作號碼 (job number),該號碼與 bash 的控制有關。# 後續的 8400 則是這個工作在系統中的 PID。至於後續出現的資料是 tar 啟動並執行資料流,# 由於我們沒有加上資料流重導向,所以會影響畫面!不過不會影響前景的操作喔!
仔細的瞧一瞧,我在輸入一個命令後,在該命令的最後面加上一個『 & 』代表將該命令丟到背景中, 此時 bash 會給予這個命令一個『工作號碼(job number)』,就是那個 [1] 啦!至於後面那個 8400 則是該命令所觸發的『 PID 』了!而且,有趣的是,我們可以繼續操作 bash 呢!很不賴吧! 不過,那麼丟到背景中的工作什麼時候完成?完成的時候會顯示什嗎?如果你輸入幾個命令後,突然出現這個資料:
[1]+ Done tar -zpcf /tmp/etc.tar.gz /etc
就代表 [1] 這個工作已經完成 (Done) ,該工作的命令則是接在後面那一串命令列。 這樣瞭解了吧!另外,這個 & 代表:『將工作丟到背景中去運行』喔! 注意到那個『運行』的字眼!此外,這樣的情況最大的好處是: 不怕被 [ctrl]+c 中斷的啦! 此外,將工作丟到背景當中要特別注意資料的流向喔!包括上面的資訊就有出現錯誤資訊,導致我的前景被影響。 雖然只要按下 [enter] 就會出現提示位元組。但如果我將剛剛那個命令改成:
[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc &
情況會怎樣?在背景當中啟動並執行命令,如果有 stdout 及 stderr 時,他的資料依舊是輸出到螢幕上面的, 所以,我們會無法看到提示位元組,當然也就無法完好的掌握前景工作。同時由於是背景工作的 tar , 此時你怎麼按下 [ctrl]+c 也無法停止螢幕被搞的花花綠綠的!所以羅,最佳的狀況就是利用資料流重導向, 將輸出資料傳送至某個檔案中。舉例來說,我可以這樣做:
[root@www ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 &[1] 8429[root@www ~]#
呵呵!如此一來,輸出的資訊都給他傳送到 /tmp/log.txt 當中,當然就不會影響到我們前景的作業了。 這樣說,您應該可以更清楚資料流重導向的重要性了吧!
將『目前』的工作丟到背景中『暫停』:[ctrl]-z
想個情況:如果我正在使用 vi ,卻發現我有個檔案不知道放在哪裡,需要到 bash 環境下進行搜尋,此時是否要結束 vi 呢?呵呵!當然不需要啊!只要暫時將 vi 給他丟到背景當中等待即可。 例如以下的案例:
[root@www ~]# vi ~/.bashrc# 在 vi 的一般模式下,按下 [ctrl]-z 這兩個按鍵[1]+ Stopped vim ~/.bashrc[root@www ~]# <==順利取得了前景的操控權![root@www ~]# find / -print....(輸出省略)....# 此時螢幕會非常的忙碌!因為螢幕上會顯示所有的檔名。請按下 [ctrl]-z 暫停[2]+ Stopped find / -print
在 vi 的一般模式下,按下 [ctrl] 及 z 這兩個按鍵,螢幕上會出現 [1] ,表示這是第一個工作, 而那個 + 代表最近一個被丟進背景的工作,且目前在背景下預設會被取用的那個工作 (與 fg 這個命令有關 )!而那個 Stopped 則代表目前這個工作的狀態。在預設的情況下,使用 [ctrl]-z 丟到背景當中的工作都是『暫停』的狀態喔!
觀察目前的背景工作狀態: jobs
[root@www ~]# jobs [-lrs]選項與參數:-l :除了列出 job number 與命令串之外,同時列出 PID 的號碼;-r :僅列出正在背景 run 的工作;-s :僅列出正在背景當中暫停 (stop) 的工作。範例一:觀察目前的 bash 當中,所有的工作,與對應的 PID[root@www ~]# jobs -l[1]- 10314 Stopped vim ~/.bashrc[2]+ 10833 Stopped find / -print
如果想要知道目前有多少的工作在背景當中,就用 jobs 這個命令吧!一般來說,直接下達 jobs 即可! 不過,如果你還想要知道該 job number 的 P識別碼,可以加上 -l 這個參數啦! 在輸出的資訊當中,例如上表,仔細看到那個 + - 號喔!那個 + 代表預設的取用工作。 所以說:『目前我有兩個工作在背景當中,兩個工作都是暫停, 而如果我僅輸入 fg 時,那麼那個 [2] 會被拿到前景當中來處理』!
其實 + 代表最近被放到背景的工作號碼, - 代表最近最後第二個被放置到背景中的工作號碼。 而超過最後第三個以後的工作,就不會有 +/- 符號存在了!
將背景工作拿到前景來處理:fg
剛剛提到的都是將工作丟到背景當中去啟動並執行,那麼有沒有可以將背景工作拿到前景來處理的? 有啊!就是那個 fg (foreground) 啦!舉例來說,我們想要將上頭範例當中的工作拿出來處理時:
[root@www ~]# fg %jobnumber選項與參數:%jobnumber :jobnumber 為工作號碼(數字)。注意,那個 % 是可有可無的!範例一:先以 jobs 觀察工作,再將工作取出:[root@www ~]# jobs[1]- 10314 Stopped vim ~/.bashrc[2]+ 10833 Stopped find / -print[root@www ~]# fg <==預設取出那個 + 的工作,亦即 [2]。立即按下[ctrl]-z[root@www ~]# fg %1 <==直接規定取出的那個工作號碼!再按下[ctrl]-z[root@www ~]# jobs[1]+ Stopped vim ~/.bashrc[2]- Stopped find / -prin
經過 fg 命令就能夠將背景工作拿到前景來處理羅!不過比較有趣的是最後一個顯示的結果,我們會發現 + 出現在第一個工作後! 怎麼會這樣啊?這是因為你剛剛利用 fg %1 將第一號工作捉到前景後又放回背景,此時最後一個被放入背景的將變成 vi 那個命令動作, 所以當然 [1] 後面就會出現 + 了!瞭解乎!另外,如果輸入『 fg - 』 則代表將 - 號的那個工作號碼拿出來,上面就是 [2]- 那個工作號碼啦!
讓工作在背景下的狀態變成運行中: bg
我們剛剛提到,那個 [ctrl]-z 可以將目前的工作丟到背景底下去『暫停』, 那麼如何讓一個工作在背景底下『 Run 』呢?我們可以在底下這個案例當中來測試! 注意喔!底下的測試要進行的快一點!
範例一:一運行 find / -perm +7000 > /tmp/text.txt 後,立刻丟到背景去暫停![root@www ~]# find / -perm +7000 > /tmp/text.txt# 此時,請立刻按下 [ctrl]-z 暫停![3]+ Stopped find / -perm +7000 > /tmp/text.txt範例二:讓該工作在背景下進行,並且觀察他!![root@www ~]# jobs ; bg %3 ; jobs[1]- Stopped vim ~/.bashrc[2] Stopped find / -print[3]+ Stopped find / -perm +7000 > /tmp/text.txt[3]+ find / -perm +7000 > /tmp/text.txt & <==用 bg%3 的情況![1]+ Stopped vim ~/.bashrc[2] Stopped find / -print[3]- Running find / -perm +7000 > /tmp/text.txt &
看到哪裡有差異嗎?呼呼!沒錯!就是那個狀態列~以經由 Stopping 變成了 Running 羅! 看到差異點,嘿嘿!命令列最後方多了一個 & 的符號羅! 代表該工作被啟動在背景當中了啦! ^_^
管理背景當中的工作: kill
剛剛我們可以讓一個已經在背景當中的工作繼續工作,也可以讓該工作以 fg 拿到前景來, 那麼,如果想要將該工作直接移除呢?或者是將該工作重新啟動呢?這個時候就得需要給予該工作一個訊號 (signal) ,讓他知道該怎麼作才好啊!此時, kill 這個命令就派上用場啦!
[root@www ~]# kill -signal %jobnumber[root@www ~]# kill -l選項與參數:-l :這個是 L 的小寫,列出目前 kill 能夠使用的訊號 (signal) 有哪些?signal :代表給予後面接的那個工作什麼樣的指示羅!用 man 7 signal 可知: -1 :重新讀取一次參數的配置檔 (類似 reload); -2 :代表與由鍵盤輸入 [ctrl]-c 同樣的動作; -9 :立刻強制移除一個工作; -15:以正常的程式方式終止一項工作。與 -9 是不一樣的。範例一:找出目前的 bash 環境下的背景工作,並將該工作『強制移除』。[root@www ~]# jobs[1]+ Stopped vim ~/.bashrc[2] Stopped find / -print[root@www ~]# kill -9 %2; jobs[1]+ Stopped vim ~/.bashrc[2] Killed find / -print# 再過幾秒你再下達 jobs 一次,就會發現 2 號工作不見了!因為被移除了!範例:找出目前的 bash 環境下的背景工作,並將該工作『正常終止』掉。[root@www ~]# jobs[1]+ Stopped vim ~/.bashrc[root@www ~]# kill -SIGTERM %1# -SIGTERM 與 -15 是一樣的!您可以使用 kill -l 來查閱!
特別留意一下, -9 這個 signal 通常是用在『強制移除一個不正常的工作』時所使用的, -15 則是以正常步驟結束一項工作(15也是預設值),兩者之間並不相同呦!舉上面的例子來說, 我用 vi 的時候,不是會產生一個 .filename.swp 的檔案嗎? 那麼,當使用 -15 這個 signal 時, vi 會嘗試以正常的步驟來結束掉該 vi 的工作, 所以 .filename.swp 會主動的被移除。但若是使用 -9 這個 signal 時,由於該 vi 工作會被強制移除掉,因此, .filename.swp 就會繼續存在檔案系統當中。這樣您應該可以稍微分辨一下了吧?
其實, kill 的妙用是很無窮的啦!他搭配 signal 所詳列的資訊 (用 man 7 signal 去查閱相關資料) 可以讓您有效管理工作與程式 (Process),此外,那個 killall 也是同樣的用法! 至於常用的 signal 您至少需要瞭解 1, 9, 15 這三個 signal 的意義才好。 此外, signal 除了以數值來表示之外,也可以使用訊號名稱喔! 舉例來說,上面的範例二就是一個例子啦!至於 signal number 與名稱的對應, 呵呵,使用 kill -l 就知道啦(L的小寫)!
另外, kill 後面接的數字預設會是 PID ,如果想要管理 bash 的工作控制,就得要加上 %數字 了, 這點也得特別留意才行喔
離線管理問題
要注意的是,我們在工作管理當中提到的『背景』指的是在終端機模式下可以避免 [crtl]-c 中斷的一個情境, 並不是放到系統的背景去喔!所以,工作管理的背景依舊與終端機有關啦! 在這樣的情況下,如果你是以遠程連線方式串連到你的 Linux 主機,並且將工作以 & 的方式放到背景去, 請問,在工作尚未結束的情況下你離線了,該工作還會繼續進行嗎?答案是『否』!不會繼續進行,而是會被中斷掉。
那怎麼辦?如果我的工作需要進行一大段時間,我又不能放置在背景底下,那該如何處理呢? 首先,你可以參考前一章的 at來處理即可!因為 at 是將工作放置到系統背景, 而與終端機無關。如果不想要使用 at 的話,那你也可以嘗試使用 nohup 這個命令來處理喔!這個 nohup 可以讓你在離線或登出系統後,還能夠讓工作繼續進行。他的文法有點像這樣:
[root@www ~]# nohup [命令與參數] <==在終端機前景中工作[root@www ~]# nohup [命令與參數] & <==在終端機背景中工作
有夠好簡單的命令吧!上述命令需要注意的是, nohup 並不支援 bash 內建的命令,因此你的命令必須要是外部命令才行。 我們來嘗試玩一下底下的任務吧!
# 1. 先編輯一支會『睡著 500 秒』的程式:[root@www ~]# vim sleep500.sh#!/bin/bash/bin/sleep 500s/bin/echo "I have slept 500 seconds."# 2. 丟到背景中去運行,並且立刻登出系統:[root@www ~]# chmod a+x sleep500.sh[root@www ~]# nohup ./sleep500.sh &[1] 5074[root@www ~]# nohup: appending output to ‘nohup.out’ <==會告知這個資訊![root@www ~]# exit
如果你再次登陸的話,再使用 pstree 去查閱你的程式,會發現 sleep500.sh 還在運行中喔!並不會被中斷掉! 這樣瞭解意思了嗎?由於我們的程式最後會輸出一個資訊,但是 nohup 與終端機其實無關了, 因此這個資訊的輸出就會被導向『 ~/nohup.out 』,所以你才會看到上述命令中,當你輸入 nohup 後, 會出現那個提示資訊羅。
如果你想要讓在背景的工作在你登出後還能夠繼續的運行,那麼使用 nohup 搭配 & 是不錯的運行情境喔! 可以參考看看!
轉自 http://vbird.dic.ksu.edu.tw/linux_basic/0440processcontrol_2.php