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