第一部分: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信號
信號 | 名稱 | 描述 |
1 | HUP | 掛起 |
2 | INT | 中斷 |
3 | QUIT | 結束運行 |
9 | KILL | 無條件終止 |
11 | SEGV | 段錯誤 |
15 | TERM | 儘可能終止 |
17 | STOP | 無條件停止運行,但不終止 |
18 | TSTP | 停止或暫停,但繼續在後臺運行 |
19 | CONT | 在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 file] time
默認情況下,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地址