shell腳本編程之控制腳本

技術(shù)交流QQ群:1027579432工扎,歡迎你的加入徘钥!

歡迎關(guān)注我的微信公眾號:CurryCoder的程序人生

1.引言

  • 目前為止,運行腳本的唯一方式是以實時模式在命令行界面上直接運行肢娘。但是呈础,這并不是Linux上運行腳本的唯一方式舆驶。

2.處理信號量

  • Linux利用信號與運行在系統(tǒng)中的進程進行通信。不同的Linux信號以及Linux如何用這些信號來停止而钞、啟動沙廉、終止進程【式冢可以通過對腳本進行編程撬陵,使其在收到特定信號時執(zhí)行某些命令,從而控制shell腳本的操作网缝。
2.1 重溫Linux信號
  • Linux系統(tǒng)和應(yīng)用程序可以生成超過30個信號巨税,下面列出了Linux編程時遇到的最常見Linux系統(tǒng)信號。
    信號                      值                          描述
    1                        SIGHUP                    掛起進程
    2                        SIGINT                    終止進程
    3                        SIGQUIT                   停止進程
    9                        SIGKILL                   無條件終止進程
    15                       SIGTERM                   盡可能終止進程
    17                       SIGSTOP                   無條件停止進程粉臊,但不是終止進程
    18                       SIGTSTP                   停止或暫停進程,但不終止進程
    19                       SIGCONT                   繼續(xù)運行停止的進程
    
  • 默認情況下,bash shell會忽略收到的任何SIGQUIT(3)和SIGTERM(15)信號(正因為如此珊蟀,交互式shell才不會意外停止)途蒋。但是,bash shell會處理收到的SIGHUP(1)和SIGINT(2)信號犀盟。
    • 如果bash shell收到了SIGHUP信號而晒,比如你要離開一個交互式shell,它就會退出阅畴。但是在退出之前倡怎,它會將SIGHUP信號傳遞給所有由該shell所啟動的進程。
    • 通過SIGINT信息贱枣,可以中斷shell监署。Linux內(nèi)核會停止為shell分配CPU處理時間。這種情況發(fā)生時纽哥,shell會將SIGINT信號傳遞給所有由它所啟動的進程钠乏。
2.2 生成信號
  • bash shell允許使用鍵盤上的組合鍵生成兩種基本的Linux信號,這個特性在需要停止或暫停失控程序時非常方便春塌。
  • 中斷進程:Ctrl+C組合鍵可以生成SIGINT信號晓避,并將該信號發(fā)送給當前在shell中運行的所有進程,停止shell中當前運行的進程只壳。如下例所示:
    $ sleep 100
    ^C
    
  • 暫停進程:可以在進程運行期間暫停進程俏拱,無需終止它。它可以在不終止進程的情況下吼句,使你能夠深入腳本內(nèi)部仔細觀察锅必。Ctrl+Z組合鍵會生成一個SIGTSTP信號,暫停shell中運行的任何進程惕艳。暫停進程與中斷進程不同:暫停進程會讓程序繼續(xù)保留在內(nèi)存中搞隐,并能從上次暫停的位置繼續(xù)運行驹愚。如下例所示:
    [njust@njust ~]$ sleep 10
    ^Z
    [1]+  已停止               sleep 10
    
  • 上述示例中,方括號中的數(shù)字是shell分配的作業(yè)號劣纲,shell將shell中運行的每個進程稱為作業(yè)逢捺,并為每個作業(yè)分配唯一的作業(yè)號。它會給第一個作業(yè)分配作業(yè)號1癞季,第二個作業(yè)分配作業(yè)號2蒸甜,依次類推。
  • 如果你的shell會話中有一個已暫停的作業(yè)余佛,在退出shell時柠新,只要再輸入一遍exit命令bash會提醒你。如下所示:
    [njust@njust ~]$ sleep 10
    ^Z
    [1]+  已停止               sleep 10
    [njust@njust ~]$ exit
    exit
    有停止的任務(wù)辉巡。
    
  • 可以還有ps命令查看已經(jīng)暫停的作業(yè)恨憎,如下所示:
    [njust@njust ~]$ sleep 10
    ^Z
    [2]+  已停止               sleep 10
    [njust@njust ~]$ ps -l
    F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S  1000   3377   3369  0  80   0 - 29140 do_wai pts/0    00:00:00 bash
    0 T  1000   3642   3377  0  80   0 - 26989 do_sig pts/0    00:00:00 sleep
    0 R  1000   3733   3377  0  80   0 - 38312 -      pts/0    00:00:00 ps
    
  • 在S列(進程狀態(tài))中,ps命令將已暫停作業(yè)的狀態(tài)顯示為T郊楣,可以通過已暫停作業(yè)的PID憔恳,就可以用kill命令來發(fā)送一個SIGKILL信號來終止它。如下例所示:
    [njust@njust ~]$ kill -9 3642
    [1]-  已殺死               sleep 10
    
2.3 捕捉信號
  • trap命令允許你來指定shell腳本要監(jiān)控并從shell中攔截的Linux信號净蚤,如果腳本收到了trap命令中列出的信號钥组,該信號不再由shell處理,而是交由本地處理今瀑。trap命令的格式如下:
    trap  commands signals
    
  • 從上述trap命令的格式來看程梦,在trap命令行上,只要列出想要shell執(zhí)行的命令橘荠,以及一組用空格分開的待捕獲的信號即可屿附。如下例所示:使用trap命令來忽略SIGINT信號,并控制腳本的行為哥童。
    #!/bin/bash
    
    trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT
    
    echo "This is a test script"
    
    count=1
    while [ $count -le 10 ]
    do
        echo "Loop #$count"
        sleep 2
        count=$[ $count +  1 ]
        done
    
    echo "This is the end of the test script"
    
    # 結(jié)果
    [njust@njust tutorials]$ ./control1.sh 
    This is a test script
    Loop #1
    Loop #2
    ^C Sorry! I have trapped Ctrl-C
    Loop #3
    Loop #4
    ^C Sorry! I have trapped Ctrl-C
    Loop #5
    Loop #6
    ^C Sorry! I have trapped Ctrl-C
    Loop #7
    Loop #8
    ^C Sorry! I have trapped Ctrl-C
    Loop #9
    Loop #10
    This is the end of the test script
    
  • 上述示例程序使用trap命令在每次檢測到SIGINT信號時挺份,會顯示一行簡單的文本消息。捕獲這些信號會阻止用戶用bash shell組合鍵來Ctrl+C來停止程序運行贮懈。
2.4 捕獲腳本退出
  • 除了在shell腳本中捕獲信號匀泊,也可以在shell腳本退出的時候進行捕獲。要想捕獲shell腳本的退出朵你,只要在trap命令后加上EXIT信號即可各聘。如下例所示:
    #!/bin/bash
    
    trap "echo Goodbye..." EXIT
    
    count=1
    while [ $count -le 5 ]
    
    do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
    done
    
  • 上述示例程序中,當腳本運行到正常的退出位置時撬呢,捕獲就被觸發(fā)伦吠,shell會執(zhí)行trap命令妆兑。如果提前退出腳本魂拦,同樣能捕獲到EXIT信號毛仪。
2.5 修改或移除捕獲
  • 如果一個信號在捕獲被修改前接收到的,那么腳本仍然會根據(jù)最初的trap命令進行處理芯勘。如下例所示:
    #!/bin/bash
    
    trap "echo ' Sorry... Ctrl-C is trapped.'" SIGINT
    
    count=1
    while [ $count -le 5 ]
    do 
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
    done
    
    trap "echo ' I modified the trap!'" SIGINT  # 此處捕捉被修改箱靴!
    
    count=1
    while [ $count -le 5 ]
    do
        echo "Second Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
    done
    
    # 結(jié)果
    [njust@njust tutorials]$ ./control3.sh 
    Loop #1
    Loop #2
    Loop #3
    Loop #4
    ^C Sorry... Ctrl-C is trapped.
    Loop #5
    Second Loop #1
    Second Loop #2
    Second Loop #3
    ^C I modified the trap!
    
  • 可以刪除已經(jīng)設(shè)置好的捕獲:只要在trap命令與希望恢復(fù)默認行為的信號列表之間加上兩個破折號即可,但如果信號是在捕獲被移除前接收到的荷愕,那么腳本會按照原先trap命令中的設(shè)置進行處理衡怀,如下例所示:
    #!/bin/bash
    
    trap "echo ' Sorry... Ctrl-C is trapped.'" SIGINT
    
    count=1
    while [ $count -le 5 ]
    do
        echo "Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
    done
    
    trap -- SIGINT   # 此處已經(jīng)刪除已經(jīng)設(shè)置好的捕獲,因此最前面設(shè)置的捕獲SIGINT信號將會失效安疗!
    echo "I just removed the trap"
    
    count=1
    while [ $count -le 5 ]
    do
        echo "Second Loop #$count"
        sleep 1
        count=$[ $count + 1 ]
    done
    
    # 結(jié)果
    [njust@njust tutorials]$ ./control4.sh 
    Loop #1
    Loop #2
    Loop #3
    ^C Sorry... Ctrl-C is trapped.
    Loop #4
    Loop #5
    I just removed the trap
    Second Loop #1
    Second Loop #2
    ^C
    

3.以后臺模式運行腳本

  • 一些腳本可能要執(zhí)行很長時間抛杨,而我們又不希望在命令行界面一直等待腳本執(zhí)行結(jié)束。于是荐类,可以采用后臺運行的模式怖现。在后臺模式中,進行運行時不會和終端會話上的STDIN玉罐、STDOUT屈嗤、STDERR關(guān)聯(lián)
3.1 后臺運行腳本
  • 以后臺模式運行腳本只需要在命令后加一個&即可吊输。如下例所示:
    #!/bin/bash
    
    count=1
    while [ $count -le 10 ]
    do
        sleep 1
        count=$[ $count + 1 ]
    done
    
    # 以后臺模式運行腳本H暮拧!季蚂!
    [njust@njust tutorials]$ ./bg1.sh &
    [1] 4280
    
  • 當&符號放到命令后時茫船,它會將命令和bash shell分離開,將命令作為系統(tǒng)中的一個獨立的后臺進行運行扭屁,結(jié)果中顯示的第一行解釋
    • [1]:shell分配給后臺進程的作業(yè)號透硝;
    • 4280:Linux系統(tǒng)分配給進程的進程ID(PID),Linux系統(tǒng)上運行的每個進程都必須有一個唯一的PID疯搅;
  • 當后臺進程結(jié)束時濒生,它會在終端上顯示出下面的一條信息,該消息表示作業(yè)的作業(yè)號及作業(yè)狀態(tài)Done幔欧,還有用于啟動作用的命令罪治。
    [1]+  完成                  ./bg1.sh
    
  • 注意:當后臺進程運行時,它仍然會使用終端顯示器來顯示STDOUT和STDERR消息礁蔗,如下例所示:
    #!/bin/bash
    
    echo "Start the test script"
    count=1
    while [ $count -le 5 ]
    do
        echo "Loop #$count"
        sleep 2 
        count=$[ $count + 1 ]
    done
    
    echo "Test script is complete"
    
    # 結(jié)果
    [njust@njust tutorials]$ ./bg2.sh &
    [1] 4712
    Start the test script
    Loop #1
    Loop #2
    Loop #3
    Loop #4
    Loop #5
    Test script is complete
    [1]+  完成                  ./bg2.sh
    
3.2 運行多個后臺作業(yè)
  • 可以在命令行中同時啟動多個后臺作業(yè)觉义,每次啟動新作業(yè)時,Linux系統(tǒng)都會為其分配一個新的作業(yè)號和PID浴井。通過ps命令晒骇,可以看出所有腳本的狀態(tài)。如下例所示:
    [njust@njust tutorials]$ ./bg2.sh &  ./bg3.sh & ./bg4.sh & ps
    [1] 5495
    [2] 5496
    [3] 5497
    Start the test script #4
    Loop #1
    Start the test script #2
    Loop #1
    Start the test script #3
    Loop #1
    PID TTY          TIME CMD
    5306 pts/0    00:00:00 bash
    5495 pts/0    00:00:00 bg2.sh
    5496 pts/0    00:00:00 bg3.sh
    5497 pts/0    00:00:00 bg4.sh
    5498 pts/0    00:00:00 ps
    5499 pts/0    00:00:00 sleep
    5500 pts/0    00:00:00 sleep
    5501 pts/0    00:00:00 sleep
    
  • 在ps命令的輸出中,每一個后臺進程都和終端會話聯(lián)系在一起洪囤。如果終端會話退出徒坡,那么后臺進程也會隨之退出。如果希望運行在后臺模式的腳本在登出控制臺后能夠繼續(xù)運行瘤缩,需要借助別的手段喇完。

4.在非控制臺下運行腳本

  • 有時候,你會想在終端會話中啟動shell腳本剥啤,然后讓腳本一直以后臺模式運行到結(jié)束锦溪,即使你已經(jīng)退出了終端「樱可以使用nohup命令來實現(xiàn)刻诊。nohup命令運行了另外一個命令來阻斷所有發(fā)送給該進程的SIGHUP信號。這會在退出終端會話時牺丙,阻止進程退出坏逢。如下例所示:
    [njust@njust tutorials]$ nohup ./bg2.sh &
    [1] 5745
    nohup: 忽略輸入并把輸出追加到"nohup.out"
    
  • 當使用nohup命令時,如果關(guān)閉該會話赘被,腳本會忽略終端會話發(fā)送過來的SIGHUP信號是整。由于nohup命令會解除終端與進程的關(guān)聯(lián),進程也就不再同STDOUT和STDERR聯(lián)系在一起民假。為了保存該命令產(chǎn)生的輸出浮入,nohup命令會自動將STDOUT和STDERR的消息重定向到一個名為nohup.out的文件中。nohup.out文件包含了通常會發(fā)送到終端顯示器上的所有輸出羊异。如下所示:
    [njust@njust tutorials]$ cat nohup.out 
    Start the test script #2
    Loop #1
    Loop #2
    Loop #3
    Loop #4
    Loop #5
    Loop #6
    Loop #7
    Loop #8
    Loop #9
    Loop #10
    Test script is complete
    

5.作業(yè)控制

  • 作業(yè)控制:啟動事秀、停止、終止及恢復(fù)作業(yè)的功能野舶。通過作業(yè)控制易迹,就能完全控制shell環(huán)境中所有進程的運行方式了。
5.1 查看作業(yè)
  • 作業(yè)控制中的關(guān)鍵命令是jobs命令平道,jobs命令允許查看shell當前正在處理的作業(yè)睹欲。如下例所示:
    #!/bin/bash
    
    echo "Script process ID: $$"
    
    count=1
    while [ $count -le 10 ]
    do
        echo "Loop #$count"
        sleep 10
        count=$[ $count + 1 ]
    done
    
    echo "End of script ..."
    
    # 結(jié)果
    [njust@njust tutorials]$ ./work1.sh 
    Script process ID: 6157
    Loop #1
    Loop #2
    ^Z
    [1]+  已停止               ./work1.sh
    
  • $$變量:顯示Linux系統(tǒng)分配給該腳本的PID∫晃荩可以從命令行啟動該腳本窘疮,使用Ctrl-Z鍵來暫停腳本。利用&將另一個作業(yè)作為后臺進程啟動冀墨,然后將腳本的結(jié)果重定向到文件中闸衫。如下所示:
    [njust@njust tutorials]$ ./work1.sh > work1.out &
    [2] 6264
    
  • jobs命令可以查看分配給shell的作業(yè),jobs命令會顯示上面兩個已停止/運行中的作業(yè)诽嘉,以及它們的作業(yè)號和作業(yè)中使用的命令蔚出。如下所示:
    [njust@njust tutorials]$ jobs
    [1]+  已停止               ./work1.sh
    [2]-  運行中               ./work1.sh > work1.out &
    
  • 要想查看作業(yè)的PID弟翘,可以在jobs命令中加入-l選項。如下所示:
    [njust@njust tutorials]$ jobs -l
    [1]+  6157 停止                  ./work1.sh
    [2]-  6264 運行中               ./work1.sh > work1.out &
    
  • jobs命令參數(shù)如下所示
    參數(shù)                    描述
    -l                 列出進程的PID和作業(yè)號
    -n                 只列出上次shell發(fā)出的通知后改變的作業(yè)
    -p                 只列出作業(yè)的PID
    -r                 只列出運行中的作業(yè)
    -s                 只列出已停止的作業(yè)
    
  • jobs命令輸出中的加號和減號骄酗,帶加號的作業(yè)會被當做默認作業(yè)稀余。在使用作業(yè)控制命令時,如果未在命令行中指定任何作業(yè)號酥筝,該作業(yè)會被當成作業(yè)控制命令的操作對象。當前的默認作業(yè)完成處理后雏门,帶減號的作業(yè)成為下一個默認作業(yè)嘿歌。任何時候都只有一個帶加號的作業(yè)和一個帶減號的作業(yè),不管shell中有多少個正在運行的作業(yè)茁影。下例表示了下一個作業(yè)在默認作業(yè)移除時是如何成為默認作業(yè)的宙帝。如下例所示:
    [njust@njust tutorials]$ ./work1.sh > work1.out &
    [1] 6721
    [njust@njust tutorials]$ ./work1.sh > work2.out &
    [2] 6729
    [njust@njust tutorials]$ ./work1.sh > work3.out &
    [3] 6738
    
    [njust@njust tutorials]$ jobs -l
    [1]   6721 運行中               ./work1.sh > work1.out &
    [2]-  6729 運行中               ./work1.sh > work2.out &
    [3]+  6738 運行中               ./work1.sh > work3.out &
    
    [njust@njust tutorials]$ kill 6738
    [3]+  已終止               ./work1.sh > work3.out
    [njust@njust tutorials]$ jobs -l
    [1]-  6721 運行中               ./work1.sh > work1.out &
    [2]+  6729 運行中               ./work1.sh > work2.out &
    
    [njust@njust tutorials]$ kill 6729
    [2]+  已終止               ./work1.sh > work2.out
    [njust@njust tutorials]$ jobs -l
    [1]+  6721 運行中               ./work1.sh > work1.out &
    
    [njust@njust tutorials]$ kill 6721
    [1]+  已終止               ./work1.sh > work1.out
    
5.2 重啟停止的作業(yè)
  • 在bash作業(yè)控制中,可以將已停止的作業(yè)作為后臺進程或前臺進程重啟募闲。前臺進程會接管你當前工作的終端步脓,所以在使用該功能時要小心。要以后臺模式重啟一個作業(yè)浩螺,可以使用bg命令加上作業(yè)號靴患。如下例所示:
    [njust@njust tutorials]$ ./work1.sh 
    Script process ID: 6956
    Loop #1
    ^Z
    [1]+  已停止               ./work1.sh
    [njust@njust tutorials]$ bg
    [1]+ ./work1.sh &
    [njust@njust tutorials]$ jobs
    [1]+  運行中               ./work1.sh &
    
  • 注意:當作業(yè)被轉(zhuǎn)入后臺模式時,并不會列出其PID要出。如果有多個作業(yè)鸳君,需要在bg命令后加上作業(yè)號患蹂。如下所示:
    [njust@njust tutorials]$ ./work1.sh 
    Script process ID: 7299
    Loop #1
    ^Z
    [1]+  已停止               ./work1.sh
    
    [njust@njust tutorials]$ ./work2.sh 
    Script process ID: 7307
    Loop #1
    ^Z
    [2]+  已停止               ./work2.sh
    
    [njust@njust tutorials]$ ./work3.sh 
    Script process ID: 7315
    Loop #1
    ^Z
    [3]+  已停止               ./work3.sh
    
    [njust@njust tutorials]$ bg 2   # bg 2用于將第二個作業(yè)置于后臺模式;蚣铡!传于!
    [2]- ./work2.sh &
    Loop #2
    
    [njust@njust tutorials]$ jobs
    [1]-  已停止               ./work1.sh
    [2]   運行中               ./work2.sh &
    [3]+  已停止               ./work3.sh
    
  • 注意:當使用jobs命令時囱挑,它列出了作業(yè)及其狀態(tài),即使是默認作業(yè)當前并沒有處于后臺模式沼溜。要以前臺模式重啟已暫停作業(yè)平挑,可使用帶有作用號的fg命令。由于作業(yè)是以前臺模式運行的系草,直到該作業(yè)完成后弹惦,命令行界面才會出現(xiàn)提示符。如下所示:
    [njust@njust tutorials]$ ./work1.sh 
    Script process ID: 7451
    Loop #1
    ^Z  
    [2]+  已停止               ./work1.sh
    
    [njust@njust tutorials]$ ./work2.sh 
    Script process ID: 7459
    Loop #1
    ^Z
    [3]+  已停止               ./work2.sh
    
    [njust@njust tutorials]$ ./work3.sh 
    Script process ID: 7467
    Loop #1
    ^Z
    [4]+  已停止               ./work3.sh
    
    [njust@njust tutorials]$ fg 2
    ./work1.sh
    Loop #2
    Loop #3
    Loop #4
    Loop #5
    Loop #6
    Loop #7
    Loop #8
    Loop #9
    Loop #10
    End of script ...
    [njust@njust tutorials]$ 
    

6.調(diào)整謙讓度

  • 在多任務(wù)操作系統(tǒng)中悄但,內(nèi)核負責將CPU時間分配給系統(tǒng)上運行的每個進程棠隐。調(diào)度優(yōu)先級是內(nèi)核分配給進程的CPU時間。在Linux系統(tǒng)中檐嚣,由shell啟動的所有進程的調(diào)度優(yōu)先級默認都是相同的助泽。
  • 調(diào)度優(yōu)先級是一個整數(shù)值啰扛,從-20(最高優(yōu)先級)~+19(最低優(yōu)先級)。默認情況下嗡贺,bash shell以優(yōu)先級0來啟動所有進程隐解。越低的值即優(yōu)先級越高,獲得CPU時間的機會就越高诫睬。
6.1 nice命令
  • nice命令允許你設(shè)置命令啟動時的調(diào)度優(yōu)先級煞茫,要讓命令以更低的優(yōu)先級允許,只要用nice -n命令來指定新的優(yōu)先級級別摄凡。如下例所示:
    [njust@njust tutorials]$ nice -n 10 ./work1.sh > work1.out &
    [1] 3484
    [njust@njust tutorials]$ ps -p 3484 -o pid,ppid,ni,cmd
    PID   PPID  NI CMD
    3484   2985  10 /bin/bash ./work1.sh
    
  • 注意:必須將nice命令和要啟動的命令放在同一行中续徽。上例中,ps命令的輸出驗證了謙讓度值(NI列)已經(jīng)被調(diào)整為10亲澡。
  • 但是钦扭,如果想要提高某個命令的優(yōu)先級,nice命令會阻止普通用戶來提高命令的優(yōu)先級床绪。因為nice命令的-n選項并不是必須的客情,只需要在破折號后面跟上優(yōu)先級即可。如下例所示:
    # 提升優(yōu)先級失敗的情況
    [njust@njust tutorials]$ nice -n -10 ./work1.sh > work1.out &
    [1] 3570
    [njust@njust tutorials]$ nice: 無法設(shè)置優(yōu)先級: 權(quán)限不夠
    ^C
    # 提升優(yōu)先級成功的情況
    [njust@njust tutorials]$ nice -10 ./work1.sh > work1.out &
    [1] 3760
    [njust@njust tutorials]$ ps -p 3760 -o pid,ppid,ni,cmd
    PID   PPID  NI CMD
    3760   2985  10 /bin/bash ./work1.sh
    
6.2 renice命令
  • 有時候需要改變系統(tǒng)上已運行命令的優(yōu)先級癞己,通過renice命令即可實現(xiàn)膀斋。它允許你指定運行進程的PID來改變它的優(yōu)先級。如下例所示:
    [root@njust tutorials]# ./work1.sh &
    [1] 4612
    Script process ID: 4612
    [root@njust tutorials]# ps -p 4612 -o pid,ppid,ni,cmd
    PID   PPID  NI CMD
    4612   4263   0 /bin/bash ./work1.sh
    [root@njust tutorials]# renice -n 10 -p 4612
    4612 (進程 ID) 舊優(yōu)先級為 0痹雅,新優(yōu)先級為 10
    [root@njust tutorials]# ps -p 4612 -o pid,ppid,ni,cmd
    PID   PPID  NI CMD
    4612   4263  10 /bin/bash ./work1.sh
    
  • renice命令會自動更新當前運行進程的調(diào)度優(yōu)先級概页,必須以root賬戶登錄后才能使用!renice也有一些限制:
    • 只能對屬于你的進程執(zhí)行renice练慕;
    • 只能通過renice降低進程的優(yōu)先級惰匙;
    • root用戶可以通過renice來任意調(diào)整進程的優(yōu)先級;

7.定時任務(wù)

  • 有時候铃将,我們需要在某個預(yù)先設(shè)定的時間開始運行腳本项鬼,Linux系統(tǒng)提供了多個在預(yù)選時間運行腳本的方法:at命令和cron表
7.1 用at命令來計劃執(zhí)行作業(yè)
  • at命令允許指定Linux系統(tǒng)何時運行腳本劲阎,at命令會將作業(yè)提交到隊列中绘盟,指定shell何時運行該作業(yè)。at的守護進程atd會以后臺模式運行悯仙,檢查作業(yè)隊列來運行作業(yè)龄毡。atd守護進程會檢查系統(tǒng)上的一個特殊目錄/var/spool/at來獲取用at命令提交的作業(yè)。默認情況下锡垄,atd守護進程會每60s檢查一下該目錄沦零。
  • 1.at命令的格式
    at [-f filename] time
    
  • 默認情況下,at命令會將STDIN的輸入放到隊列中货岭。可以使用-f選項來指定用于讀取命令(腳本文件)的文件名路操。time參數(shù)指定了Linux系統(tǒng)何時運行該作業(yè)疾渴。如果你指定的時間已經(jīng)錯過,at命令會在第二天的那個時刻運行指定的作業(yè)屯仗。
  • 如何指定時間搞坝?at命令能夠識別多種不同的時間格式。如下所示:
    • 標準的小時和分鐘格式魁袜,如21:00桩撮;
    • AM/PM指示符,如21:00 PM峰弹;
    • 特定可命令時間店量,如now noon midnight等;
    • 標準日期格式垮卓,如MMDDYY MM/DD/YY DD.MM.YY
    • 文本日期垫桂,如Jul 4或Dec 25师幕;
    • 指定時間增量:
      • 當前時間+25 min粟按;
      • 明天10:15 PM;
      • 10:15+7天霹粥;
  • 在使用at命令時灭将,該作業(yè)會被提交到作業(yè)隊列中。作業(yè)隊列會保存通過at命令提交的待處理的作業(yè)后控。針對不同的優(yōu)先級庙曙,存在26種不同的作業(yè)隊列,作業(yè)隊列通過用小寫字母az和大寫字母AZ來表示浩淘。作業(yè)隊列的字母排序越高捌朴,作業(yè)運行的優(yōu)先級就越低(更高的nice值)。默認情況下张抄,at的作業(yè)會被提交到a作業(yè)隊列砂蔽。如果想以更高的優(yōu)先級運行作業(yè),可以用-q參數(shù)指定不同的隊列字母署惯。
  • 2.獲取作業(yè)的輸出
  • 當作業(yè)在Linux系統(tǒng)上運行時左驾,顯示器并不會關(guān)聯(lián)到該作業(yè)。取而代之的是极谊,Linux系統(tǒng)會將提交該作業(yè)的用戶的電子郵箱地址作為STDOUT和STDERR诡右。任何發(fā)到STDOUT或STDERR的輸出都會通過郵件發(fā)送給該用戶。如下例所示:
    #!/bin/bash
    
    echo "This script run at $(date +%B%d,%T)"
    sleep 5
    echo "This is the script's end"
    
    # 結(jié)果
    [njust@njust tutorials]$ at -f at.sh now
    job 1 at Mon May 18 21:15:00 2020
    您在 /var/spool/mail/njust 中有新郵件
    
  • 使用e-mail作為at命令的輸出很不方便轻猖,因此在使用at命令時帆吻,最好在腳本中對STDOUT和STDERR進行重定向。如果不想在at命令中使用郵件或重定向咙边,最好加上-M選項來屏蔽作業(yè)產(chǎn)生的輸出信息桅锄。如下所示:
    #!/bin/bash
    
    echo "This script run at $(date +%B%d,%T)" > at1.out
    echo >> at1.out
    sleep 3
    echo "This is the script's end" >> at1.out
    
    # 結(jié)果
    [njust@njust tutorials]$ at -M -f at1.sh now
    job 4 at Mon May 18 21:20:00 2020
    [njust@njust tutorials]$ cat at1.out 
    This script run at 五月18,21:20:29
    
    This is the script's end
    [njust@njust tutorials]$ cat at1.sh 
    
  • 3.列出等待的作業(yè)
  • atq命令可以查看系統(tǒng)中有哪些作業(yè)在等待琉雳。如下所示:
    [njust@njust tutorials]$ at -M -f at1.sh teatime
    job 5 at Tue May 19 16:00:00 2020
    [njust@njust tutorials]$ at -M -f at1.sh tomorrow
    job 6 at Tue May 19 21:23:00 2020
    [njust@njust tutorials]$ at -M -f at1.sh 23:00
    job 7 at Mon May 18 23:00:00 2020
    [njust@njust tutorials]$ at -M -f at1.sh now
    job 8 at Mon May 18 21:24:00 2020
    
    [njust@njust tutorials]$ atq
    5   Tue May 19 16:00:00 2020 a njust
    6   Tue May 19 21:23:00 2020 a njust
    7   Mon May 18 23:00:00 2020 a njust
    
  • 4.刪除作業(yè)
  • 一旦知道哪些作業(yè)在作業(yè)隊列中等待,就能使用atrm命令來刪除等待中的命令友瘤。如下所示:
    [njust@njust tutorials]$ atq
    5   Tue May 19 16:00:00 2020 a njust
    6   Tue May 19 21:23:00 2020 a njust
    7   Mon May 18 23:00:00 2020 a njust
    [njust@njust tutorials]$ atrm 5
    [njust@njust tutorials]$ atq
    6   Tue May 19 21:23:00 2020 a njust
    7   Mon May 18 23:00:00 2020 a njust
    
7.2 安排需要定期執(zhí)行的腳本
  • 使用at命令預(yù)設(shè)時間安排腳本執(zhí)行很方便翠肘,但是如果想每天的同一時間都執(zhí)行該腳本,就不再使用at命令不斷提交作業(yè)了辫秧。Linux系統(tǒng)使用cron程序來安排要定期執(zhí)行的作業(yè)束倍。cron程序會在后臺運行并檢查一個特殊的表(cron時間表),以獲得已安排執(zhí)行的作業(yè)盟戏。
  • 1.cron時間表:cron時間表采用一種特別的格式來指定作業(yè)何時運行绪妹,格式如下所示:
    min hour day month week 具體的命令
    
  • cron時間表允許你使用特定值、取值范圍(如1~5)或者通配符(*)來指定條目柿究。如下所示:
    15 10 * * * command  # 每天的10:15執(zhí)行一次命令
    
  • 可以用三字符的文本值(mon邮旷、tue、wed蝇摸、thu婶肩、fri、sat貌夕、sun)或數(shù)值(0為周日律歼,6為周六)來指定week的值。如何設(shè)置一個在每個月的最后一天執(zhí)行的命令啡专?常用的方法是加一條使用date命令的if-then語句來檢查明天的日期是否為01险毁。如下所示:
    00 12 * * * if [ `date +%d -d tomorrow` = 01 ]; then ; command
    
  • 具體的命令中必須指定要運行的命令或腳本的全路徑名,如下例所示:
    15 10 * * * /home/njust/tutotials/test.sh > test.out
    
  • 2.構(gòu)建cron時間表
  • 每個系統(tǒng)用戶都可以用自己的cron時間表來運行安排好的任務(wù)们童,Linux提供了crontab命令來處理cron時間表畔况。要列出已有的cron時間表,可以用-l選項慧库。如下所示:
    [njust@njust tutorials]$ crontab -l
    no crontab for njust
    
  • 默認情況下跷跪,用戶cron時間表文件并不存在。要為cron時間表添加條目完沪,可以用-e選項域庇。在添加條目時,crontab命令會啟動一個文本編輯器覆积,使用已有的cron時間表作為文件內(nèi)容听皿。
  • 3.瀏覽cron目錄
  • 如果你創(chuàng)建的腳本對精確的執(zhí)行時間要求不高,用預(yù)配置的cron腳本目錄會更方便宽档。有4個基本目錄:hourly尉姨、daily、monthly吗冤、weekly又厉。如果腳本需要每天執(zhí)行一次九府,只要將腳本復(fù)制到daily目錄,cron就會每天執(zhí)行它覆致。如下所示:
    [njust@njust ~]$ ls /etc/cron.*ly
    /etc/cron.daily:
    logrotate  man-db.cron  mlocate
    
    /etc/cron.hourly:
    0anacron  mcelog.cron
    
    /etc/cron.monthly:
    
    /etc/cron.weekly:
    

4.anacron程序

  • cron程序的唯一問題是:它假設(shè)Linux是7*24小時運行的侄旬,除非將Linux系統(tǒng)當成服務(wù)器環(huán)境來運行,否則假設(shè)不會成立煌妈。如果某個作業(yè)在cron時間表中安排運行的時間已到儡羔,但這時Linux系統(tǒng)處于關(guān)機狀態(tài),那么這個作業(yè)就不會執(zhí)行璧诵。當系統(tǒng)開機時汰蜘,cron程序不會再去運行那些錯過的作業(yè)。要解決這個問題之宿,許多Linux發(fā)行版包含了anacron程序族操。
  • 如果anacron知道某個作業(yè)錯過了執(zhí)行時間,它會盡快運行該作業(yè)比被。這個功能常用于日志維護的腳本色难。anacron程序只會處理位于cron目錄的程序,如/etc/cron.monthly姐赡。它使用時間戳來決定作業(yè)是否在正確的計劃間隔內(nèi)運行莱预。每個cron目錄都有一個時間戳文件柠掂,該文件位于/var/spool/anacron项滑。如下所示:
    [root@njust njust]# cat /var/spool/anacron/cron.monthly
    20200517
    
  • anacron程序使用自己的時間表(通常位于/etc/anacrontab)來檢查作業(yè)目錄。如下所示:
    [root@njust njust]# cat /etc/anacrontab
    # /etc/anacrontab: configuration file for anacron
    
    # See anacron(8) and anacrontab(5) for details.
    
    SHELL=/bin/sh
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    # the maximal random delay added to the base delay of the jobs
    RANDOM_DELAY=45
    # the jobs will be started during the following hours only
    START_HOURS_RANGE=3-22
    
    #period in days   delay in minutes   job-identifier   command
    1   5   cron.daily      nice run-parts /etc/cron.daily
    7   25  cron.weekly     nice run-parts /etc/cron.weekly
    @monthly 45 cron.monthly        nice run-parts /etc/cron.monthly
    
  • anacron時間表的基本格式如下所示:
    • period:定義了作業(yè)多久運行一次涯贞,以天為單位枪狂。anacron程序用此來檢查作業(yè)的時間戳文件;
    • delay:指定系統(tǒng)啟動后anacron程序需要等待多少分鐘再開始運行錯過的腳本宋渔;
    • command:包含了run-parts程序(負責運行目錄中傳給它的任何腳本)和一個cron腳本目錄名州疾;
    • identifier:一種特別的非空字符串,用于唯一標識日志消息和錯誤郵件中的作業(yè)皇拣;
    period delay identifier command
    
  • 注意:anacron程序不會運行位于 /etc/cron.hourly的腳本严蓖。因為anacron程序不會處理執(zhí)行時間需求小于一天的腳本
7.3 使用新shell啟動腳本
  • 如果每次運行腳本的時候都能夠啟動一個新的bash shell氧急,將會非常方便颗胡。當用戶登錄bash shell時需要運行相關(guān)的啟動文件,基本上不同發(fā)行版的Linux系統(tǒng)按照下列順序所找到的第一個文件會被運行吩坝,其余的文件將會被忽略:
    • $HOME/.bash_profile
    • $HOME/.bash_login
    • $HOME/.profile
  • 因此毒姨,需要將在登錄時運行的腳本放在上面的第一個文件中。每次啟動一個新的shell時钉寝,bash shell都會運行.bashrc文件弧呐≌⒚裕可以如下例所示進行驗證:
    # .bashrc
    
    # Source global definitions
    if [ -f /etc/bashrc ]; then
        . /etc/bashrc
    fi
    
    # Uncomment the following line if you don't like systemctl's auto-paging feature:
    # export SYSTEMD_PAGER=
    
    # User specific aliases and functions
    
    echo "I'm in a new shell!"
    
    # 結(jié)果
    [njust@njust ~]$ bash
    I'm in a new shell!
    
  • .bashrc文件通常也是通過某個bash啟動文件來運行的。因為.bashrc文件會運行兩次:一次是當你登入bash shell時俘枫,另一次是當你啟動一個bash shell時腥沽。如果你需要一個腳本在兩個時刻都得以運行,可以把這個腳本放進該文件中鸠蚪。

8.資料下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市邓嘹,隨后出現(xiàn)的幾起案子酣栈,更是在濱河造成了極大的恐慌,老刑警劉巖汹押,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矿筝,死亡現(xiàn)場離奇詭異,居然都是意外死亡棚贾,警方通過查閱死者的電腦和手機窖维,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妙痹,“玉大人铸史,你說我怎么就攤上這事∏右粒” “怎么了琳轿?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耿芹。 經(jīng)常有香客問我崭篡,道長,這世上最難降的妖魔是什么吧秕? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任琉闪,我火速辦了婚禮,結(jié)果婚禮上砸彬,老公的妹妹穿的比我還像新娘颠毙。我一直安慰自己,他們只是感情好砂碉,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布蛀蜜。 她就那樣靜靜地躺著,像睡著了一般绽淘。 火紅的嫁衣襯著肌膚如雪涵防。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機與錄音壮池,去河邊找鬼偏瓤。 笑死,一個胖子當著我的面吹牛椰憋,可吹牛的內(nèi)容都是我干的厅克。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼橙依,長吁一口氣:“原來是場噩夢啊……” “哼证舟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窗骑,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤女责,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后创译,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抵知,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年软族,在試婚紗的時候發(fā)現(xiàn)自己被綠了刷喜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡立砸,死狀恐怖掖疮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颗祝,我是刑警寧澤浊闪,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站吐葵,受9級特大地震影響规揪,放射性物質(zhì)發(fā)生泄漏桥氏。R本人自食惡果不足惜温峭,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望字支。 院中可真熱鬧凤藏,春花似錦、人聲如沸堕伪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欠雌。三九已至蹄梢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間富俄,已是汗流浹背禁炒。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工而咆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人幕袱。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓暴备,卻偏偏與公主長得像,于是被迫代替她去往敵國和親们豌。 傳聞我的和親對象是個殘疾皇子涯捻,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354