10個 Linux/Unix下 Bash 和 KSH shell 的作業控制實例
Linux 和 Unix 屬於多任務的操作系統,也就是說一個系統在同一時間段內能運行多重任務(進程)。在這個新的博客系列,我將會列出相關的 Linux 和 Unix 作業(job)控制的命令,你可以通過這些命令在 Bash 或 Korn 還有 POSIX shell 下實現執行多重任務。
什麼是作業控制?
作業控制不只是能夠停止/掛起(stop/suspend)正在執行的進程(命令),也可以繼續/喚醒(continue/resume)執行你需要的每一個進程。這完全可以用你的操作系統和 bash/ksh 之類的 shell 或 POSIX shell 完成。
誰給作業控制的提供了環境?
Bash / Korn shell,或者是 POSIX shell 提供給了作業控制的環境。
跟作業表打個招呼吧
你的 shell 會留有一張當前作業的表單,稱為作業表。當你鍵入命令時,shell 會給它分配一個 jobID(也稱作 JOBSPEC)。一個 jobID 或 JOBSPEC只是很小的整數數值。
1: 創建你的首個 Linux/Unix 作業
我要運行一個名為 xeyes 的命令,它會在屏幕上顯示兩個橢圓的眼睛,輸入: $ xeyes &
輸出樣例:
Fig.01: 在後台運行 xeyes 命令
我使用&符號讓一個 job 在後台運行。shell 會列印一行信息類似如下:
[1] 6891
在這個例子中,有兩個數字輸出,分別表示:
- 1 : 在後台執行的 xeyes 任務的作業號為 1。
- 6891 : 作業1的進程ID。
我在多執行一些 job:
## 啟動一個文本編輯器,X 的系統負載顯示,和 sleep 命令 ##
gedit /tmp/hello.c &
xload &
sleep 100000 &
2: 列出當前的作業
要查看當前 shell 的激活的任務狀態,輸入:
$ jobs
$ jobs -l
輸出如下:
[1] 9379 Running xeyes &
[2] 9380 Running gedit /tmp/hello.c &
[3]- 9420 Running xload &
[4]+ 9421 Running sleep 100000 &
簡要描述如下:
欄位 | 值 | 描述 | 示例 |
---|---|---|---|
1 | [1] | jobID 或 JOB_SPEC - 工作號要與fg, bg, wait, kill和其他shell命令一起使用。你必須在工作號前綴添加一個百分號:(**%** )。加號 (+ ) 標識著默認的或是現在的作業。減號 (- ) 標識著前一個作業。 |
%1 fg %1 kill %2 |
2 | 9379 | 進程 ID - 系統自動為每個進程創建並分配地獨有的身份標誌號。 | kill 9379 |
3 | Running | 狀態 - 關於作業的狀態:**Running** - 該 作業正在運行,還沒有被外部信號掛起。**Stopped** - 該作業已經被掛起。 |
N/A |
4 | xeyes & | command - 由shell給出的命令。 | script &firefox url& |
你也可以用 ps 命名列出當前系統正在運行的進程:
$ ps
3: 停止或掛起正在運行的作業
按下[Ctrl]-[Z]鍵或使用kill 命令,如下所示:
kill -s stop PID
舉個例子,啟動ping 命令,然後用 Ctrl-Z 鍵來停止 ping 命令作業:
Animated gif 01: 掛起 ping 命令作業
4: 在前台恢復 掛起的/停止的作業
讓我們恢復處於停止狀態下的作業,讓它回到前台繼續運行,要將其變成當前作業,必須藉助fg 命令。具體語法如下:
## ping 命令的作業號的值為5 ##
fg %5
我也可以規定命令行開端符合字元串"ping"的作業[譯註:不能出現不明確的字元串,例如如果後台有兩個 vim 進程而你敲入 fg %vim 會報錯。]:
## %String ##
fg %ping
輸出樣例:
64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=3 ttl=53 time=265 ms
64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=4 ttl=53 time=249 ms
64 bytes from www.cyberciti.biz (75.126.153.206): icmp_req=5 ttl=53 time=267 ms
^C
5: 在後台恢復 掛起/停止狀態的作業
在這個例子中,我使用yum 命令更新所有安裝在 Redhat 或 CentOS Linux 生產伺服器上的軟體包並置於後台作業。
# yum -y update &>/root/patch.log &
然而,由於一些原因(例如,過載問題)我決定停止這個作業20分鐘:
# kill -s stop %yum
輸出樣例:
[7]+ Stopped yum -y update &>/root/patch.log &
用 bg 重啟停止在後台的 yum 進程
現在,我將要恢復停止的 yum -y update &>/root/patch.log & 作業,鍵入:
# bg %7
或者:
# bg %yum
輸出樣例:
[7]+ yum -y update &>/root/patch.log &
6: 殺死作業/進程
殺死yum 命令進程,輸入如下kill 命令及其作業號 7:
# kill %7
或者
# kill 進程ID
輸出樣例:
[7]+ Terminated yum -y update &>/root/patch.log &
在 Linux/FreeBSD/OS X Unix 下你也可以使用 killall 命令通過名字殺死進程或是 jobID 而不是通過 PID
7 為什麼當我登出後 shell 會清除我的所有後台作業
在這個例子中,我將會啟動 pdfwriter.py 來批量生成這個站點的 pdf 文件:
~/scripts/www/pdfwriter.py --profile=faq --type=clean --header=logo
--footer-left "nixCraft is GIT UL++++ W+++ C++++ M+ e+++ d-"
--footer-right "Page [of] of [total]" &
一旦當我登出shell時,pdfwriter.py 作業就會被我的 shell 殺死。為了克服這個問題需要使用shell的內置命令 disown 來告訴 shell 不要發送 HUP 信號,鍵入:
$ ~/scripts/www/pdfwriter.py --profile=faq .... &
$ disown
$ exit
8 使用一個名為 nohup 的外部命令阻止在登出時殺死作業
你也可以使用nohup 命令在你退出 shell 後執行作業:
$ nohup ~/scripts/www/pdfwriter.py --profile=faq .... &
$ exit
9: 查找最後的作業的 PID
為了查找最近在後台執行的(非同步)命令的進程ID,可使用 bash shell 的特殊參數 $!
$ gedit foo.txt &
$ echo "最近在後台執行的job 的PID - $!"
輸出樣例:
最近在後台執行的job 的PID - 9421
10: 等候作業完成
wait 命令會等候給予的進程ID 或 作業ID指定的進程,然後報告它的終止狀態。語法如下:
/path/to/large-job/command/foo &
wait $!
/path/to/next/job/that-is-dependents/on-foo-command/bar
這是我的一個工作腳本:
#!/bin/bash
# A shell script wrapper to create pdf files for our blog/faq section
########################################################################
# init() - Must be run first
# Purpose - Create index file in $_tmp for all our wordpress databases
########################################################################
init(){
_php="/usr/bin/php"
_phpargs="-d apc.enabled=0"
_base="~/scripts"
_tmp="$_base/tmp"
_what="$1"
for i in $_what
do
[[ ! -d "$_tmp/$i" ]] && /bin/mkdir "$_tmp/$i"
$_php $_phpargs -f "$_base/php/rawsqlmaster${i}.php" > "$_tmp/$i/output.txt"
done
}
#####################################################
# Without index file, we can out generate pdf files
#####################################################
init blog
###########################################################
# Do not run the rest of the script until init() finished
###########################################################
wait $!
## Alright, create pdf files
~/scripts/www/pdfwriter.py --profile=blog --type=clean --header=logo
--footer-left "nixCraft is GIT UL++++ W+++ C++++ M+ e+++ d-"
--footer-right "Page [of] of [total]"
Linux 和 Unix 作業控制命令總結列表
命令 | 描述 | 示例 |
---|---|---|
**&** |
將作業置入後台 | 命令 & |
**%n** |
設置作業號為 n (數字)的作業 | 命令 %1 |
**%Word** |
引用命令行開端包含 Word 的作業 | 命令 %yum |
**%?Word** |
引用命令行包含 Word 的作業 | 命令 %?ping |
**%%** **%+** |
引用當前作業 | kill %%kill %+ |
**%-** |
引用先前作業 | bg %- |
**CTRL-Z** kill -s stop jobID
|
||
**jobs** jobs -l
|
||
**bg** |
將 作業置入後台 | bg %1bg %ping |
**fg** |
將作業置入前台 | fg %2fg %apt-get |
關於 shell 內置命令和外部命令的小注
運行下面的 type 命令找出給予命令是否屬於內部或外部的。
type -a fg bg jobs disown
輸出樣式:
fg is a shell builtin
fg is /usr/bin/fg
bg is a shell builtin
bg is /usr/bin/bg
jobs is a shell builtin
jobs is /usr/bin/jobs
disown is a shell builtin
在幾乎所有情況下,你都需要使用 shell 的內置命令。所有外部命令例如 /usr/bin/fg 或 /usr/bin/jobs 工作在一個不同的 shell 環境下,而不能用在父 shell 的環境下。
總結
我希望你能喜歡這篇博文系列(rss 訂閱),我建議你閱讀下面的更多信息:
- 在我們的 faq 章節查閱有關進程管理的文章disoen 命令示例,jobs 命令示例,bg 命令示例,和fg 命令示例。
- Man pages bash(1), ksh(1), ps(1), kill(1)
- Korn shell (ksh93) 文檔.
- NU bash shell 文檔.
我會計劃在這個系列添加更多深入的教程。若果你需要看到具體的主題,請在下方評論讓我知道。
via: http://www.cyberciti.biz/howto/unix-linux-job-control-command-examples-for-bash-ksh-shell/
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive