Linux?Shell任務(wù)控制的實(shí)現(xiàn)示例
通常情況下運(yùn)行腳本的方式就是以實(shí)時(shí)模式在命令行界面上直接運(yùn)行,除此之外還有很多其他的運(yùn)行腳本的方式,如后臺(tái)運(yùn)行,定時(shí)運(yùn)行等等。除運(yùn)行方式外,還可以對(duì)腳本程序的運(yùn)行進(jìn)行控制,包括向腳本發(fā)送信號(hào)、修改腳本的優(yōu)先級(jí)以及在腳本運(yùn)行時(shí)從暫停切換到運(yùn)行模式。
1)信號(hào)
Linux
利用信號(hào)與運(yùn)行在系統(tǒng)中的進(jìn)程進(jìn)行通信,可以通過對(duì)腳本進(jìn)行編程,使其在收到特定信號(hào)時(shí)執(zhí)行特定命令。
信號(hào) | 值 | 描述 |
---|---|---|
1 | SIGHUP | 掛起進(jìn)程 |
2 | SIGINT | 終止進(jìn)程 |
3 | SIGQUIT | 停止進(jìn)程 |
9 | SIGKILL | 無條件終止進(jìn)程 |
15 | SIGTERM | 盡可能終止進(jìn)程 |
17 | SIGSTOP | 無條件停止進(jìn)程,但不是終止進(jìn)程 |
18 | SIGTSTP | 停止或暫停進(jìn)程,但不終止進(jìn)程 |
19 | SIGCONT | 繼續(xù)運(yùn)行停止的進(jìn)程 |
默認(rèn)情況下,交互式shell
終端本身的進(jìn)程會(huì)忽略收到的任何 SIGQUIT (3)
和 SIGTERM (5)
信號(hào),因此其不會(huì)被意外終止。
如果bash shell
收到了 SIGHUP
信號(hào),比如當(dāng)要離開一個(gè)交互式shell
時(shí),它就會(huì)退出。但在退出之前,它會(huì)將 SIGHUP
信號(hào)傳給所有由該shell
所啟動(dòng)的進(jìn)程。
通過鍵盤生成信號(hào)
Ctrl+C
組合鍵會(huì)生成 SIGINT
信號(hào),并將其發(fā)送給當(dāng)前在shell
中運(yùn)行的所有進(jìn)程。
Ctrl+Z
組合鍵會(huì)生成一個(gè) SIGTSTP
信號(hào),停止shell
中運(yùn)行的任何進(jìn)程。這樣可以在進(jìn)程運(yùn)行期間暫停進(jìn)程,而無需終止它。這樣可以在不終止進(jìn)程的情況下使用戶深入腳本內(nèi)部一窺究竟。
停止進(jìn)程會(huì)讓程序繼續(xù)保留在內(nèi)存中,并能從上次停止的位置繼續(xù)運(yùn)行。
要想啟動(dòng)停止的進(jìn)程可以使用fg
或bg
在前臺(tái)和后臺(tái)啟動(dòng)。
$ sleep 100 # ^Z # [1]+ 已停止 sleep 100
方括號(hào)中的數(shù)字是shell
分配的作業(yè)號(hào) (job number)
。
可以用 ps
命令來查看已停止的作業(yè)。
$ ps -l # F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD # 0 T 1001 116014 113239 0 80 0 - 2791 do_sig pts/0 00:00:00 sleep
在 S
列中(進(jìn)程狀態(tài)), ps
命令將已停止作業(yè)的狀態(tài)為顯示為 T
。這說明命令要么被跟蹤,要么被停止了。
在有已停止作業(yè)存在的情況下退出shell
會(huì)終止已停止作業(yè)。
trap 命令捕獲信號(hào)
trap
命令允許用戶來指定shell
腳本要監(jiān)視并從shell
中攔截的Linux
信號(hào)。當(dāng)腳本收到了 trap
命令中列出的信號(hào),會(huì)執(zhí)行用戶指定的操作。
trap
命令的格式:
trap commands signals
示例,
#!/bin/bash trap "echo 'Ctrl-C Pressed'" SIGINT echo This is a test c=1 while [ $c -le 5 ] do echo "Loop #$c" sleep 1 c=$[ $c + 1 ] done
執(zhí)行,
$ ./test.sh # This is a test # Loop #1 # Loop #2 # ^CCtrl-C Pressed # Loop #3 # Loop #4 # Loop #5
上面腳本中trap
命令會(huì)在每次檢測(cè)到 SIGINT
信號(hào)時(shí)捕獲這些信號(hào),阻止用戶用bash shell
組合鍵Ctrl+C
來停止程序。
除了在shell
腳本中捕獲中斷信號(hào),也可以在shell
腳本退出時(shí)捕獲退出信號(hào)EXIT
。以在shell
完成任務(wù)時(shí)執(zhí)行特定的命令。
#!/bin/bash trap "echo 'Running Finished.'" EXIT echo This is a test c=1 while [ $c -le 5 ] do echo "Loop #$c" sleep 1 c=$[ $c + 1 ] done
執(zhí)行,
$ ./test.sh # This is a test # Loop #1 # Loop #2 # Loop #3 # Loop #4 # Loop #5 # Running Finished.
要修改移除捕獲,在腳本中的不同位置進(jìn)行不同的捕獲處理,只需重新使用帶有新選項(xiàng)的 trap
命令。
#!/bin/bash trap "echo 'Caught SIGINT'" SIGINT echo "This is first caughtion of SIGINT" c=1 while [ $c -le 3 ] do echo "Loop #$c" sleep 1 c=$[ $c + 1 ] done trap "echo 'Redefine SIGINT '" SIGINT echo "This is Mutated caughtion of SIGINT" sleep 10
執(zhí)行,
$ ./test.sh # This is first caughtion of SIGINT # Loop #1 # ^CCaught SIGINT # Loop #2 # Loop #3 # This is Mutated caughtion of SIGINT # ^CRedefine SIGINT
修改了信號(hào)捕獲之后,腳本處理信號(hào)的方式就會(huì)發(fā)生變化。如果一個(gè)信號(hào)是在捕獲被修改前接收到的,那么腳本仍然會(huì)根據(jù)最初的 trap
命令進(jìn)行處理。
想刪除已設(shè)置好的捕獲,只需要在 trap
命令與希望恢復(fù)默認(rèn)行為的信號(hào)列表之間加上兩個(gè)破折號(hào)即可。
trap -- SIGINT
2)在后臺(tái)運(yùn)行腳本
直接在命令行界面運(yùn)行shell
腳本,腳本在運(yùn)行時(shí),沒法在終端會(huì)話里做別的事情。
在用 ps
命令時(shí),會(huì)看到運(yùn)行在Linux
系統(tǒng)上的一系列不同進(jìn)程。這些進(jìn)程顯然都不是運(yùn)行在當(dāng)前的終端顯示器上的,這種模式稱為在后臺(tái)運(yùn)行進(jìn)程。在后臺(tái)模式中,進(jìn)程運(yùn)行時(shí)不會(huì)和終端會(huì)話上的 STDIN
、 STDOUT
以及 STDERR
關(guān)聯(lián)。
命令后加 & 符
前面介紹過,以后臺(tái)模式運(yùn)行shell
腳本,只要在命令后加個(gè) & 符就行。
$ ./test.sh & # [1] 118347
方括號(hào)中的數(shù)字是shell
分配給后臺(tái)進(jìn)程的作業(yè)號(hào)。下一個(gè)數(shù)是Linux
系統(tǒng)分配給進(jìn)程的進(jìn)程ID(PID)
。當(dāng)后臺(tái)進(jìn)程結(jié)束時(shí),它會(huì)在終端上顯示出一條消息:
# [1]+ 已完成 ./test.sh
通過./test.sh &
命令將腳本放在后臺(tái)運(yùn)行還存在兩個(gè)問題,一個(gè)是當(dāng)前bash shell
終端關(guān)閉時(shí)后臺(tái)運(yùn)行中的進(jìn)程仍然會(huì)被終止,第二個(gè)時(shí)放入后臺(tái)的腳本輸出仍然會(huì)顯示在顯示器上,會(huì)與新輸入命令的輸入混淆在一起。
運(yùn)行多個(gè)后臺(tái)作業(yè)時(shí),通過 ps
命令,可以看到
所有腳本處于運(yùn)行狀態(tài)。
./test.sh & ./test.sh &
$ ps # F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD # 0 S 1001 118703 118697 0 80 0 - 3178 do_wai pts/3 00:00:00 test.sh # 0 S 1001 118707 118703 0 80 0 - 2791 hrtime pts/3 00:00:00 sleep # 0 S 1001 118714 118697 0 80 0 - 3178 do_wai pts/3 00:00:00 test.sh # 0 S 1001 118718 118714 0 80 0 - 2791 hrtime pts/3 00:00:00 sleep
使用nohub命令
當(dāng)需要在終端會(huì)話中啟動(dòng)shell
腳本,然后讓腳本一直以后臺(tái)模式運(yùn)行到結(jié)束,且終端會(huì)話退出仍不影響腳本運(yùn)行時(shí),前面介紹的&
符號(hào)的方式就不適合了,這時(shí)需要使用nohub
命令。
nohup
命令運(yùn)行的后臺(tái)任務(wù)會(huì)阻斷所有發(fā)送給該進(jìn)程的 SIGHUP
信號(hào),這可以在退出終端會(huì)話時(shí)阻止進(jìn)程退出。
nohup
命令的格式:
$ nohup ./test.sh & # [1] 119226 # nohup: 忽略輸入并把輸出追加到'nohup.out'
由于 nohup
命令會(huì)解除終端與進(jìn)程的關(guān)聯(lián),進(jìn)程也就不再同 STDOUT
和 STDERR
聯(lián)系在一起。
為了保存該命令產(chǎn)生的輸出, nohup
命令會(huì)自動(dòng)將 STDOUT
和 STDERR
的消息重定向到一個(gè)名為nohup.out
的文件中。值得注意的是,當(dāng)在同個(gè)目錄同時(shí)啟動(dòng)多個(gè)nohub
命令時(shí),會(huì)輸出到同一個(gè)nohub.out
文件中。
3)作業(yè)控制
jobs
命令可以查看分配給shell
的作業(yè)。
通過test.sh
啟動(dòng)兩個(gè)作業(yè),
$ ./test.sh # This is first caughtion of SIGINT # Loop #1 # ^Z # [1]+ 已停止 $ ./test.sh > test.out & # [2] 119480 $ jobs # [1]+ 已停止 ./test.sh # [2]- 運(yùn)行中 ./test.sh > test.out &
要想查看作業(yè)的PID
,可以在 jobs
命令中加入 -l
選項(xiàng)。jobs
命令輸出中的加號(hào)和減號(hào)的含義是帶加號(hào)的作業(yè)會(huì)被當(dāng)做默認(rèn)作業(yè),在使用作業(yè)控制命令時(shí),如果未在命令行指定任何作業(yè)號(hào),該作業(yè)會(huì)被當(dāng)成作業(yè)控制命令的操作對(duì)象。當(dāng)前的默認(rèn)作業(yè)完成處理后,帶減號(hào)的作業(yè)成為下一個(gè)默認(rèn)作業(yè)。任何時(shí)候都只有一個(gè)帶加
號(hào)的作業(yè)和一個(gè)帶減號(hào)的作業(yè)。在前面介紹的重新啟動(dòng)停止的作業(yè)的命令fg/bg
不帶參數(shù)時(shí),啟動(dòng)的就是+
號(hào)對(duì)應(yīng)的作業(yè)。
更多jobs
命令的選項(xiàng)參數(shù),可以通過命令jobs --help
查看。
4)調(diào)度優(yōu)先級(jí)
調(diào)度優(yōu)先級(jí)決定了內(nèi)核分配給進(jìn)程的CPU時(shí)間。在Linux
系統(tǒng)中,由shell
啟動(dòng)的所有進(jìn)程的調(diào)度優(yōu)先級(jí)默認(rèn)都是相同的,都是0
。調(diào)度優(yōu)先級(jí)是個(gè)整數(shù)值,從-?20
(最高優(yōu)先級(jí))到+19
(最低優(yōu)先級(jí))。
要改變一個(gè)shell
腳本的優(yōu)先級(jí),可以通過 nice
命令做到。
nice命令
nice
命令允許你設(shè)置命令啟動(dòng)時(shí)的調(diào)度優(yōu)先級(jí)。要讓命令以更低的優(yōu)先級(jí)運(yùn)行,只要用 nice
的 -n
命令行來指定新的優(yōu)先級(jí)即可。
$ nice -n 10 ./test.sh > test.out & # [2] 120413 $ ps -p 120413 -o pid,ppid,ni,cmd # PID PPID NI CMD # 120413 118697 10 /bin/bash ./test.sh
通過ps
命令可以看到調(diào)度優(yōu)先級(jí)已經(jīng)被調(diào)整到了10
。
nice
命令阻止普通系統(tǒng)用戶來提高命令的優(yōu)先級(jí),需要使用root
權(quán)限。
renice 命令
renice
命令用來改變系統(tǒng)上已運(yùn)行命令的優(yōu)先級(jí)。通過指定運(yùn)行進(jìn)程的PID來改變它的優(yōu)先級(jí)。
$ renice -n 10 -p 120756 # 120756 (process ID) 舊優(yōu)先級(jí)為 0,新優(yōu)先級(jí)為 10
5)定時(shí)運(yùn)行作業(yè)
Linux
系統(tǒng)提供了多個(gè)在預(yù)選時(shí)間運(yùn)行腳本的方法: at
命令和 cron
表。
at
at
命令允許指定Linux
系統(tǒng)何時(shí)運(yùn)行腳本,相當(dāng)于是預(yù)約執(zhí)行任務(wù)。
at
的守護(hù)進(jìn)程 atd
會(huì)以后臺(tái)模式運(yùn)行,檢查作業(yè)隊(duì)列來運(yùn)行作業(yè)。大多數(shù)Linux
發(fā)行版會(huì)在啟動(dòng)時(shí)運(yùn)行此守護(hù)進(jìn)程。
atd
守護(hù)進(jìn)程會(huì)檢查系統(tǒng)上的一個(gè)特殊目錄(通常位于/var/spool/at
)來獲取用 at
命令提交的作業(yè)。默認(rèn)情況下, atd
守護(hù)進(jìn)程會(huì)每60秒檢查一下這個(gè)目錄。有作業(yè)時(shí), atd
守護(hù)進(jìn)程會(huì)檢查作業(yè)設(shè)置運(yùn)行的時(shí)間。如果時(shí)間跟當(dāng)前時(shí)間匹配, atd` 守護(hù)進(jìn)程就會(huì)運(yùn)行此作業(yè)。
at
命令的基本格式:
at [-f filename] time
-f
參數(shù)來指定用于讀取命令(腳本文件)的文件名。time
參數(shù)指定了Linux系統(tǒng)何時(shí)運(yùn)行該作業(yè)。
at
命令能識(shí)別多種不同的時(shí)間格式:
- 標(biāo)準(zhǔn)的小時(shí)和分鐘格式,比如
22:15
AM/PM
指示符,比如10:15 PM
- 特定可命名時(shí)間,比如
now
、noon
、midnight
或者teatime(4 PM)
- 通過不同的日期格式指定特定的日期
- 標(biāo)準(zhǔn)日期格式,比如MMDDYY、MM/DD/YY或DD.MM.YY
- 文本日期,比如Jul 4或Dec 25,加不加年份均可
- 指定時(shí)間增量:當(dāng)前時(shí)間+25 min。
$ at -f test.sh 21:23 # warning: commands will be executed using /bin/sh # job 3 at Mon Jan 8 21:23:00 2024
作業(yè)隊(duì)列的字母排序越高,作業(yè)運(yùn)行的優(yōu)先級(jí)就越低,nice
值更高。默認(rèn)情況下, at
的作業(yè)會(huì)被提交到 a
作業(yè)隊(duì)列。如果想以更高優(yōu)先級(jí)運(yùn)行作業(yè),可以用 -q
參數(shù)指定不同的隊(duì)列字母。
在使用 at
命令時(shí),最好在腳本中對(duì) STDOUT
和 STDERR
進(jìn)行重定向。
atq
命令可以查看系統(tǒng)中有哪些作業(yè)在等待。
$ atq # 1 Mon Jan 8 21:17:00 2024 = rob # 6 Tue Jan 9 20:24:00 2024 a rob # 3 Mon Jan 8 21:23:00 2024 = rob # 4 Tue Jan 9 20:24:00 2024 a rob # 5 Tue Jan 9 20:24:00 2024 a rob
可以用 atrm
命令來刪除等待中的作業(yè)。
$ atrm 6 $ atq # 1 Mon Jan 8 21:17:00 2024 = rob # 3 Mon Jan 8 21:23:00 2024 = rob # 4 Tue Jan 9 20:24:00 2024 a rob # 5 Tue Jan 9 20:24:00 2024 a rob
定期執(zhí)行命令
at
命令可以在預(yù)設(shè)時(shí)間安排腳本執(zhí)行,但如果需要腳本在每天的同一時(shí)間運(yùn)行或是每周一次、每月一次就需要使用新方法。
Linux
系統(tǒng)使用cron
程序來安排要定期執(zhí)行的作業(yè)。 cron
程序會(huì)在后臺(tái)運(yùn)行并檢查cron
時(shí)間表,以獲知已安排執(zhí)行的作業(yè)。
可以使用crontab -e
來編輯cron
時(shí)間表:
$ crontab -e # GNU nano 4.8 /tmp/crontab.hABXZo/crontab # # Edit this file to introduce tasks to be run by cron. # # # # Each task to run has to be defined through a single line # # indicating with different fields when the task will be run # # and what command to run for the task
表中每一行表示一個(gè)定期執(zhí)行的任務(wù),其格式為:
# m h dom mon dow command
m
表示分鐘,
h表示小時(shí),
dom表示幾號(hào),
mon表示月份,
dow表示星期幾,
*`表示任意日期。
分別是:minute (m), hour (h), day of month (dom), month (mon),# and day of week (dow) or use '*' in these fields (for 'any')
示例:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
表示每周一凌晨5點(diǎn)將home.tgz
解壓到/home
路徑中。
每月最后一天執(zhí)行的任務(wù)設(shè)置方式,
# 00 12 * * * if [ ` date +%d -d tomorrow ` = 01 ] ; then ; command
列出crontab
中的任務(wù):
crontab -l
如果待執(zhí)行的腳本對(duì)精確的執(zhí)行時(shí)間要求不高,用預(yù)配置的cron腳本目錄會(huì)更方便。在/etc/
路徑下有4個(gè)基本目錄:cron.hourly、daily、monthly
和weekly
。譬如,如果腳本需要每天運(yùn)行一次,只要將腳本復(fù)制到daily
目錄,cron
就會(huì)每天執(zhí)行它。
cron
程序的唯一問題是它假定Linux系統(tǒng)是7×24小時(shí)運(yùn)行的,如果系統(tǒng)存在關(guān)機(jī)重啟,有可能會(huì)錯(cuò)誤定時(shí)任務(wù),處理這種情況最好是能在開機(jī)時(shí)檢查是否有錯(cuò)過的定時(shí)任務(wù),而cron
并不會(huì)去檢查,很多Linux
發(fā)行版還包含了anacron
程序可以解決這個(gè)問題。
anacron
程序只會(huì)處理位于cron
目錄的程序,比如/etc/cron.monthly
。它用時(shí)間戳來決定作業(yè)是否在正確的計(jì)劃間隔內(nèi)運(yùn)行了。每個(gè)cron
目錄都有個(gè)時(shí)間戳文件,該文件位于/var/spool/anacron
。
$ sudo cat /var/spool/anacron/cron.monthly # 20240104
到此這篇關(guān)于Linux Shell任務(wù)控制的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Linux Shell任務(wù)控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Linux 編程之進(jìn)程fork()詳解及實(shí)例
這篇文章主要介紹了Linux 編程之進(jìn)程fork()詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03linux shell 腳本實(shí)現(xiàn)tcp/upd協(xié)議通訊(重定向應(yīng)用)
這篇文章主要介紹了linux shell 腳本實(shí)現(xiàn)tcp/upd協(xié)議通訊(重定向應(yīng)用),需要的朋友可以參考下2015-10-10Shell腳本實(shí)現(xiàn)刪除郵件隊(duì)列
這篇文章主要介紹了Shell腳本實(shí)現(xiàn)刪除郵件隊(duì)列,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-02-02通過shell腳本對(duì)mysql的增刪改查及my.cnf的配置
這篇文章主要介紹了通過shell腳本對(duì)mysql的增刪改查及my.cnf的配置,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07Linux在shell中自動(dòng)生成1到100的數(shù)組方法(兩種方法)
之前自己在寫shell腳本的時(shí)候,需要自動(dòng)創(chuàng)建1-100的文本確不知道該如何去創(chuàng)建。今天小編給大家分享兩種方法,需要的朋友參考下2017-02-02Shell腳本實(shí)現(xiàn)上傳zip壓縮文件到FTP服務(wù)器
這篇文章主要介紹了Shell腳本實(shí)現(xiàn)上傳zip壓縮文件到FTP服務(wù)器,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-12-12