《Linux命令行與shell腳本編程大全》 第十五章 學習筆記

第一部分:Linux命令行
《Linux命令行與shell腳本編程大全》 第一章:初識Linux shell
《Linux命令行與shell腳本編程大全》 第二章:走進shell
《Linux命令行與shell腳本編程大全》 第三章:基本的bash shell命令
《Linux命令行與shell腳本編程大全》 第四章:更多的bash shell命令
《Linux命令行與shell腳本編程大全》 第五章:使用Linux環境變量
《Linux命令行與shell腳本編程大全》 第六章:理解Linux文件權限
《Linux命令行與shell腳本編程大全》 第七章:管理文件系統
《Linux命令行與shell腳本編程大全》 第八章:安裝軟件程序
《Linux命令行與shell腳本編程大全》 第九章:使用編輯器

第二部分:shell腳本編程基礎
《Linux命令行與shell腳本編程大全》 第十章:構建基本腳本
《Linux命令行與shell腳本編程大全》 第十一章:使用結構化命令
《Linux命令行與shell腳本編程大全》 第十二章:更多的結構化命令
《Linux命令行與shell腳本編程大全》 第十三章:處理用戶輸入
《Linux命令行與shell腳本編程大全》 第十四章:呈現數據
《Linux命令行與shell腳本編程大全》 第十五章:控制腳本

第三部分:高級shell編程
《Linux命令行與shell腳本編程大全》 第十六章:創建函數
《Linux命令行與shell腳本編程大全》 第十七章:圖形化桌面上的腳本編程
《Linux命令行與shell腳本編程大全》 第十八章:初識sed和gawk
《Linux命令行與shell腳本編程大全》 第十九章:正則表達式
《Linux命令行與shell腳本編程大全》 第二十章:sed進階
《Linux命令行與shell腳本編程大全》 第二十一章:gawk進階
《Linux命令行與shell腳本編程大全》 第二十二章:使用其他shell

第四部分:高級shell腳本編程主題
《Linux命令行與shell腳本編程大全》 第二十三章:使用數據庫
《Linux命令行與shell腳本編程大全》 第二十四章:使用Web
《Linux命令行與shell腳本編程大全》 第二十五章:使用E-mail
《Linux命令行與shell腳本編程大全》 第二十六章:編寫腳本實用工具
《Linux命令行與shell腳本編程大全》 第二十七章:shell腳本編程進階


第十五章:控制腳本


處理信號

重溫Linux信號

信號名稱描述
1HUP掛起
2INT中斷
3QUIT結束運行
9KILL無條件終止
11SEGV段錯誤
15TERM儘可能終止
17STOP無條件停止運行,但不終止
18TSTP停止或暫停,但繼續在後臺運行
19CONT在STOP或TSTP之後恢復執行

默認情況下,bash shell會忽略收到的任何SIGQUIT(3)和SIGTERM(5)信號。

如果bash shell收到了SIGHUP信號,它會退出。但是在退出之前,它會將SIGHUP信號傳給shell啓動的所有進程(比如shell腳本)。通過SIGINT可以中斷shell。Linux內核會停止將CPU的處理時間分配給shell。此時,shell會將SIGINT信號傳給shell啓動的所有進程。

注意:shell會將這些信號傳給shell腳本程序來處理,而shell腳本的默認行爲是忽略這些信號。

 

產生信號

終止進程

CTRL+C會生成SIGINT信號

暫停進程

CTRL+Z會生成SIGSTP信號

$ gedit a
^Z
[1]+  Stopped                 gedit a

這裏看到有一個作業產生,狀態爲stopped

關於作業講解可參看(#1)

可以用ps查看已停止的作業,然後用kill將其終止。

捕捉信號

trap commands signal

指定shell腳本觀察的信號並攔截

#!/bin/bash
trap "echo you can\'t stop me!" SIGINT

count=1
while [ $count -le 10 ]
do
    echo "Loop #$count"
    count=$[ $count + 1]
    sleep 5
done

執行腳本時候按下CTRL+C,那麼此時腳本不會終止,而是打出log

$ signal_test 
Loop #1
^Cyou can't stop me!
Loop #2
^Cyou can't stop me!
……

雖然不能終止它,但是發現,本來應該sleep 5秒的,CTRL+C之後,這次sleep就馬上結束了

捕捉腳本的退出

同上面一樣,只需把trap捕捉的信號改爲EXIT即可

trap "echo bye!" EXIT

當腳本退出的時候則會輸出:

$ signal_test 
Loop #1
^Cbye!

移出捕捉

trap - signals

在連詞線後面加信號即可。

 

以後臺模式運行腳本

後臺運行腳本

只需在命令後加&即可

此時會輸出作業ID和進程ID

$ gedit signal_test &
[1] 9651

運行多個後臺作業

$ gedit redirect_test &
[2] 9689
[1]   Done                    gedit signal_test
$ signal_test &
[3] 9699

通過ps au可以看到程序執行情況

1000      9689  2.5  0.4 395676 29944 pts/0    Sl   20:12   0:00 gedit redirect_test

1000      9699  0.0  0.0  13624  1468 pts/0    S    20:12   0:00 /bin/bash ./signal_test

退出終端

通過ps的輸出,可以看到每個後臺進程都綁定到了該終端會話的終端上了(pts/0).如果進程會話退出了,後臺進程也會退出。

退出終端時,如果有關聯到終端的還在運行的後臺進程,有的終端模擬器會提醒你,但不是全部。

在非控制檯下運行腳本

nohup命令可以幫助你使得腳本一直在後臺運行,直到其完成,即使退出了終端會話。

nohup command args...

$ nohup gedit signal_test &
[1] 9878
$ nohup: ignoring input and appending output to `nohup.out'

如果關閉該會話,腳本會忽略任何終端發過來的SIGHUP信號

由於nohup命令會從終端解除進程的關聯,進程會丟掉到STDOUT和STDERR的鏈接。

爲了保存輸出,nohup會自動將STDOUT和STDERR重定向到名爲nohup.out的文件中

注意:如果使用nohup執行了多個命令,那麼這些輸出都會重定向到nohup.out中!

 

作業控制

啓動、停止、無條件終止以及恢復作業的這些功能統稱爲作業控制。

查看作業

jobs可以列出分配給shell的作業

-l:列出進程的PID以及作業號

-n:只列出上次shell發出的通知後改變了狀態的作業

-p:只列出作業的PID

-r:只列出運行中的作業

-s:只列出已停止的作業

$ gedit test.xml &
[1] 5463
$ jobs
[1]+  Running                 gedit test.xml &

帶加號的作業會被當成默認的作業。使用作業命令時,如果未指定作業號,那麼該作業會被當做操作對象。

帶減號的作業會在當前默認作業處理完畢的時候成爲下一個默認作業。

任何時候都不會有超過1個的帶加號的作業和帶減號的作業

$ signal_test 
Loop #1
^Z
[1]+  Stopped                 signal_test
$ signal_test 
Loop #1
^Z
[2]+  Stopped                 signal_test
$ signal_test 
Loop #1
^Z
[3]+  Stopped                 signal_test
$ jobs -l
[1]   5596 Stopped                 signal_test
[2]-  5598 Stopped                 signal_test
[3]+  5602 Stopped                 signal_test
$ kill -9 5602
$ jobs -l
[1]-  5596 Stopped                 signal_test
[2]+  5598 Stopped                 signal_test

kill了3號任務之後,之前帶減號的2號任務就變成了當前的任務

重啓停止的作業

bg jobid:在後臺重啓任務

fg jobid:在前臺重啓任務

(fg、bg更多講解可參看(#1))

調整謙讓度

調度優先級是個整數,從-20(最高優先級)到20(最低優先級)。默認情況下,bash shell以優先級=0啓動所有進程。

nice命令

nice -n level command

普通用戶無法設置更高優先級,會得到如下錯誤

$ nice -n -1 gedit 
nice: cannot set niceness: Permission denied

renice命令

renice level -p pid

使用renice時需要注意:

1.只能對屬於你的進程執行

2.只能降低優先級

3.root用戶可以隨意調整任何進程任何優先級

 

定時運行作業

atd守護進程會檢查系統上的一個特殊目錄(通常爲/var/spool/at。我機器上面沒有這個目錄,在我機器上應該是/var/spool/cron/atjobs)

默認情況下,atd守護進程會每60s檢查一下這個目錄。有作業時,atd守護進程會檢查作業設置運行的時間。

at命令的格式

at [-f filetime

默認情況下,at會將STDIN的輸入放到隊列中。-f可以指定執行的腳本文件。

下面是at可以識別的時間格式:

標準小時和分鐘,比如10:11

~AM/~PM指示符,比如10:32~PM

特定可命名的時間:比如now、noon、midnight、teatime(4~PM)

如果指定的時間已經過去了,那麼at會在第二天這個時候執行

 

標準日期格式:比如MMDDYY、MM/DD/YY、DD.MM.YY

文本日期,比如Jul 4,有無年份均可

 

也可指定時間增量

當前時間+25min

明天11:32~PM

11:50+4天

使用at命令,作業會被提交到作業隊列(job queue)中。有26種不同優先級的隊列,用小寫a-z表示。

作業隊列字母排序越高,優先級就越低。可以使用-q執行優先級。

$ at -f for_test noon
warning: commands will be executed using /bin/sh
job 8 at Thu Aug 29 12:00:00 2013
$ sudo ls /var/spool/cron/atjobs/
a00008015e6130
$ at -q c -f for_test noon
warning: commands will be executed using /bin/sh
job 9 at Thu Aug 29 12:00:00 2013
$ sudo ls /var/spool/cron/atjobs/
a00008015e6130	c00009015e6130

當任務執行完畢的時候,/var/spool/cron/atjobs/下的文件會被刪除

注意:

使用at的時候,我們會發現有這樣一行log輸出

warning: commands will be executed using /bin/sh

也就是說,系統會用/bin/sh來執行腳本,而不是使用bash!

這樣就會遇到一些問題,足以讓人崩潰。

大多數:inux發行版中,賦給/bin/sh的默認shell是bash shell,但是Ubuntu將dash shell作爲其默認shell。

爲了使用bash執行腳本,我們需要做個wrapper

bash /home/su1216/android/source/linux_learned/for_test

保存爲文件,我這裏命名它爲bash_wrapper

然後用at執行此腳本即可

$ at -f bash_wrapper now
warning: commands will be executed using /bin/sh
job 27 at Thu Aug 29 16:08:00 2013

這個時候,世界將恢復正常。

獲取作業的輸出

作業運行時,屏幕不會有輸出。系統會將提交作業的用戶Email作爲STDOUT和STDERR。

在機器上要安裝mailutils

之後執行mail,可能會出現下面的問題:

$ mail
Cannot open mailbox /var/mail/su1216: Permission denied
No mail for su1216

可以按着下列步驟解決:

sudo touch /var/mail/$USER
sudo chown $USER:mail /var/mail/$USER
sudo chmod o-r /var/mail/$USER
sudo chmod g+rw /var/mail/$USER

上面的命令之前都已經講過,意義分別爲

創建/var/mail/$USER文件

改變屬主

去除其他用戶的讀權限

給屬組增加讀寫權限

列出等待的作業

atq可以列出等待的作業

$ atq
30	Fri Aug 30 16:28:00 2013 a su1216

刪除作業

atrm job

注意:只能刪除自己提交的作業

計劃定期執行腳本

Linux系統使用cron來定期執行作業。cron會在後臺運行並檢查稱作cron時間表(cron table)來獲得計劃執行的作業。

cron時間表

cron時間表格式如下:

min hour dayofmonth month dayofweek command

cron時間表允許使用特定的值、範圍、通配符指定時間。比如:

15 10 * * * command

dayofmonth、month和dayofweek字段中使用通配符,表示字段值的可以取到的全集。上面表示在每天的10:15都要執行command

可以使用三字符文本值(mon、tue……)或者數值(0=週日,6=週六)指定dayofweek

注意:如何指定每月的最後一天

可以使用date來查看明天的日期是不是01

00 12 *  * * if [ `date +%d -d tomorrow` = 01 ] ; then ; command

在每天上午12點的時候檢查明天是不是01

cron時間表必須指定命令的全路徑。可以添加任何參數和重定向符號

 

cron程序是假定Linux是7*24小時運行的!

如果腳本還沒有執行,系統就關閉了,過了執行時間再開啓機器,那麼cron是不會執行過期的腳本的。

構建cron時間表

每個用戶都有自己的cron時間表

crontab -l:列出當前用戶的cron時間表,默認cron時間表是不存在的。可以使用-e參數來添加條目。

cron目錄

當不要求有精確的時間執行腳本時,用預配置的cron腳本目錄會更方便。

有4個基本目錄

$ ls /etc/cron.*ly
/etc/cron.daily:
0anacron  apport  apt  bsdmainutils  dpkg  exim4-base  logrotate  man-db  mlocate  popularity-contest  quota  samba  standard

/etc/cron.hourly:

/etc/cron.monthly:
0anacron

/etc/cron.weekly:
0anacron  apt-xapian-index  cvs  man-db

每天執行一次,則只需把腳本拷貝到/etc/cron.daily下面即可。

anacron程序

anacron和cron不同,他會處理因爲關機而過期的任務。

anacron只會處理cron目錄的程序。它用時間戳來決定作業是否在適當的計劃間隔內運行了。每個cron目錄都有時間戳文件,位於/var/spool/anacron

anacron程序有自己的用來檢查作業目錄的表,通常位於/etc/anacrontab

anacron時間表於cron時間表格式不同,具體如下:

period delay identifier command

period單位爲天,delay系統啓動多少分鐘後,anacron開始執行錯過的腳本。command包括run-parts程序和一個cron腳本目錄。run-parts程序負責運行目錄中傳給它的任何腳本。

注意:anacron不會運行位於/etc/cron.hourly的腳本

identifier是一個特殊的非空白字符串,它用於唯一識別日誌消息和錯誤Email中的作業。

下面是我機器上面的anacrontab

$ cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron

# See anacron(8) and anacrontab(5) for details.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# These replace cron's entries
1	5	cron.daily	 nice run-parts --report /etc/cron.daily
7	10	cron.weekly	 nice run-parts --report /etc/cron.weekly
@monthly	15	cron.monthly nice run-parts --report /etc/cron.monthly

 

啓動時運行

開機時運行腳本

開機過程

開始運行Linux系統時,Linux內核會加載到內存中並運行。它做的第一件事是開始UNIX System V過程或Upstart init過程(具體取決於發行版和版本)。然後這個過程將負責啓動Linux系統上所有其他進程。

System V init過程

System V init過程會讀取/etc/inittab文件。inittab文件會列出系統的運行級(run level)

基於Red Hat發行版的Linux運行級別

運行級別描述
0關機
1單用戶模式
2多用戶模式,通常不支持網絡
3全功能多用戶模式,支持網絡
4可定義用戶
5多用戶模式,支持網絡和圖形化X Window會話
6重啓

基於Debian發行版的Linux運行級別(包括Ubuntu、Linux Mint等)

運行級別描述
0關機
1單用戶模式
2-5多用戶模式,支持網絡和圖形化X Window會話
6重啓

Ubuntu沒有/etc/inittab文件,默認情況下會以運行級別2啓動系統,想要修改,需要自行創建/etc/inittab文件

有些Linux發行版將開機腳本放在/etc/rc#.d,其中#代表運行級別。有些放在/etc/init.d,有些放在/etc/init.d/rc.d下面

Upstart init過程

Upstart不關注系統運行級別,而關注時間。

在Upstart中,系統開機稱爲開機事件(startup event)。

Upstart使用位於/etc/event.d或/etc/init目錄下的文件來啓動進程,具體取決於發行版和版本。

爲了向後兼容,許多Upstart實現仍會調用較早的位於/etc/init.d以及/etc/rc#.d目錄中的System V init腳本

定義自己的開機腳本

Linux本地開機文件位置

發行版文件位置
debian/etc/init.d/rc.local
Fedora/etc/rc.d/rc.local
Mandriva/etc/rc.local
OpenSure/etc/init.d/boot.local
Ubuntu/etc/rc.local

可以修改本地開機文件,使用腳本時,必須指定腳本的全路徑。

警告:不同Linux發行版在開機過程的不同事件執行該本地開機腳本。有時該腳本會在網絡支持等啓動前運行。

在新shell中啓動

bash shell會用主目錄下的兩個文件.bash_profile和.bashrc來自動啓動腳本並設置環境變量

當新shell是新的登錄生成的話,bash shell會運行.bash_profile文件。可以把任何登錄時要運行的腳本放到該文件中。

當新shell啓動時,包括有新的登錄的情況,bash shell 會運行.bashrc文件。

如果想爲系統中所有用戶運行一個腳本。大多數Linux發行版提供了/etc/bashrc文件

更多登錄shell和非登錄shell內容參見(#2



1.《Unix & Linux 大學教程》 - 第二十六章 進程和作業控制

2.《Unix & Linux 大學教程》 - 第十四章:使用shell:初始化文件



轉貼請保留以下鏈接

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章