鍍金池/ 教程/ Linux/ shell 腳本
初步進(jìn)入 linux 世界
Linux 系統(tǒng)的遠(yuǎn)程登錄
配置 Tomcat
配置 samba 服務(wù)器
LNMP 環(huán)境搭建
配置 FTP 服務(wù)
linux 系統(tǒng)用戶以及用戶組管理
正則表達(dá)式
LAMP環(huán)境搭建
安裝 RPM 包或者安裝源碼包
NFS 服務(wù)配置
文檔的壓縮與打包
Linux 操作系統(tǒng)的安裝
配置 squid 服務(wù)
Linux 文件與目錄管理
Linux 磁盤管理
學(xué)會(huì)使用簡(jiǎn)單的 MySQL 操作
關(guān)于 Linux 的歷史
學(xué)習(xí) shell 腳本之前的基礎(chǔ)知識(shí)
圖形界面還是命令窗口
文本編輯工具 vim
shell 腳本
使用 Nagios 搭建監(jiān)控服務(wù)器
linux 系統(tǒng)日常管理

shell 腳本

終于到shell 腳本這章了,在以前筆者賣了好多關(guān)子說(shuō)shell腳本怎么怎么重要,確實(shí)shell腳本在linux系統(tǒng)管理員的運(yùn)維工作中非常非常重要。下面筆者就帶你正式進(jìn)入shell腳本的世界吧。

到現(xiàn)在為止,你明白什么是shell腳本嗎?如果明白最好了,不明白也沒(méi)有關(guān)系,相信隨著學(xué)習(xí)的深入你就會(huì)越來(lái)越了解到底什么是shell腳本。首先它是一個(gè)腳本,并不能作為正式的編程語(yǔ)言。因?yàn)槭桥茉?/span>linuxshell中,所以叫shell腳本。說(shuō)白了,shell腳本就是一些命令的集合。舉個(gè)例子,我想實(shí)現(xiàn)這樣的操作:1)進(jìn)入到/tmp/目錄;2)列出當(dāng)前目錄中所有的文件名;3)把所有當(dāng)前的文件拷貝到/root/目錄下;4)刪除當(dāng)前目錄下所有的文件。簡(jiǎn)單的4步在shell窗口中需要你敲4次命令,按4次回車這樣是不是很麻煩?當(dāng)然這4步操作非常簡(jiǎn)單,如果是更加復(fù)雜的命令設(shè)置需要幾十次操作呢?那樣的話一次一次敲鍵盤會(huì)很麻煩。所以不妨把所有的操作都記錄到一個(gè)文檔中,然后去調(diào)用文檔中的命令,這樣一步操作就可以完成。其實(shí)這個(gè)文檔呢就是shell腳本了,只是這個(gè)shell腳本有它特殊的格式。

Shell腳本能幫助我們很方便的去管理服務(wù)器,因?yàn)槲覀兛梢灾付ㄒ粋€(gè)任務(wù)計(jì)劃定時(shí)去執(zhí)行某一個(gè)shell腳本實(shí)現(xiàn)我們想要需求。這對(duì)于linux系統(tǒng)管理員來(lái)說(shuō)是一件非常值得自豪的事情。現(xiàn)在的139郵箱很好用,發(fā)郵件的同時(shí)還可以發(fā)一條郵件通知的短信給用戶,利用這點(diǎn),我們就可以在我們的linux服務(wù)器上部署監(jiān)控的shell腳本,比如網(wǎng)卡流量有異常了或者服務(wù)器web服務(wù)器停止了就可以發(fā)一封郵件給管理員,同時(shí)發(fā)送給管理員一個(gè)報(bào)警短信這樣可以讓我們及時(shí)的知道服務(wù)器出問(wèn)題了。

有一個(gè)問(wèn)題需要約定一下,凡是自定義的腳本建議放到/usr/local/sbin/目錄下,這樣做的目的是,一來(lái)可以更好的管理文檔;二來(lái)以后接管你的管理員都知道自定義腳本放在哪里,方便維護(hù)。

shell腳本的基本結(jié)構(gòu)以及如何執(zhí)行

http://wiki.jikexueyuan.com/project/linux/images/14_1.png.jpg" alt="14_1.png.jpg" />

Shell腳本通常都是以.sh 為后綴名的,這個(gè)并不是說(shuō)不帶.sh這個(gè)腳本就不能執(zhí)行,只是大家的一個(gè)習(xí)慣而已。所以,以后你發(fā)現(xiàn)了.sh為后綴的文件那么它一定會(huì)是一個(gè)shell腳本了。test.sh中第一行一定是 “#! /bin/bash” 它代表的意思是,該文件使用的是bash語(yǔ)法。如果不設(shè)置該行,那么你的shell腳本就不能被執(zhí)行?!?’表示注釋,在前面講過(guò)的后面跟一些該腳本的相關(guān)注釋內(nèi)容以及作者和創(chuàng)建日期或者版本等等。當(dāng)然這些注釋并非必須的,如果你懶的很,可以省略掉,但是筆者不建議省略。因?yàn)殡S著你工作時(shí)間的增加,你寫的shell腳本也會(huì)越來(lái)越多,如果有一天你回頭查看你寫的某個(gè)腳本時(shí),很有可能忘記該腳本是用來(lái)干什么的以及什么時(shí)候?qū)懙?/span>所以寫上注釋是有必要的。另外系統(tǒng)管理員并非你一個(gè),如果是其他管理員查看你的腳本,他看不懂豈不是很郁悶該腳本再往下面則為要運(yùn)行的命令了。

http://wiki.jikexueyuan.com/project/linux/images/14_7.png.jpg" alt="14_7.png.jpg" />

Shell腳本的執(zhí)行很簡(jiǎn)單,直接”sh filename “ 即可,另外你還可以這樣執(zhí)行

http://wiki.jikexueyuan.com/project/linux/images/14_8.png.jpg" alt="14_8.png.jpg" />

默認(rèn)我們用vim編輯的文檔是不帶有執(zhí)行權(quán)限的,所以需要加一個(gè)執(zhí)行權(quán)限,那樣就可以直接使用’./filename’ 執(zhí)行這個(gè)腳本了。另外使用sh命令去執(zhí)行一個(gè)shell腳本的時(shí)候是可以加-x選項(xiàng)來(lái)查看這個(gè)腳本執(zhí)行過(guò)程的,這樣有利于我們調(diào)試這個(gè)腳本哪里出了問(wèn)題。

http://wiki.jikexueyuan.com/project/linux/images/14_9.png.jpg" alt="14_9.png.jpg" />

shell腳本中用到了’date’這個(gè)命令,它的作用就是用來(lái)打印當(dāng)前系統(tǒng)的時(shí)間。其實(shí)在shell腳本中date使用率非常高。有幾個(gè)選項(xiàng)筆者常常在shell腳本中用到:

http://wiki.jikexueyuan.com/project/linux/images/14_10.png.jpg" alt="14_10.png.jpg" />

%Y表示年,%m表示月,%d表示日期,%H表示小時(shí),%M表示分鐘,%S表示秒

http://wiki.jikexueyuan.com/project/linux/images/14_11.png.jpg" alt="14_11.png.jpg" />

注意%y%Y的區(qū)別。

http://wiki.jikexueyuan.com/project/linux/images/14_21.png.jpg" alt="14_21.png.jpg" />

-d 選項(xiàng)也是經(jīng)常要用到的,它可以打印n天前或者n天后的日期,當(dāng)然也可以打印n個(gè)月/年前或者后的日期。

http://wiki.jikexueyuan.com/project/linux/images/14_22.png.jpg" alt="14_22.png.jpg" />

另外星期幾也是常用的

http://wiki.jikexueyuan.com/project/linux/images/14_23.png.jpg" alt="14_23.png.jpg" />

【shell腳本中的變量

shell腳本中使用變量顯得我們的腳本更加專業(yè)更像是一門語(yǔ)言,開(kāi)個(gè)玩笑,變量的作用當(dāng)然不是為了專業(yè)。如果你寫了一個(gè)長(zhǎng)達(dá)1000行的shell腳本,并且腳本中出現(xiàn)了某一個(gè)命令或者路徑幾百次。突然你覺(jué)得路徑不對(duì)想換一下,那豈不是要更改幾百次?你固然可以使用批量替換的命令,但是也是很麻煩,并且腳本顯得臃腫了很多。變量的作用就是用來(lái)解決這個(gè)問(wèn)題的

http://wiki.jikexueyuan.com/project/linux/images/14_24.png.jpg" alt="14_24.png.jpg" />

test2.sh中使用到了反引號(hào),你是否還記得它的作用?’d’’d1’在腳本中作為變量出現(xiàn),定義變量的格式為 變量名=變量的值”。當(dāng)在腳本中引用變量時(shí)需要加上’$’符號(hào),這跟前面講的在shell中自定義變量是一致的。下面看看腳本執(zhí)行結(jié)果吧。

http://wiki.jikexueyuan.com/project/linux/images/14_25.png.jpg" alt="14_25.png.jpg" />

下面我們用shell計(jì)算兩個(gè)數(shù)的和

http://wiki.jikexueyuan.com/project/linux/images/14_26.png.jpg" alt="14_26.png.jpg" />

數(shù)學(xué)計(jì)算要用’[ ]’括起來(lái)并且外頭要帶一個(gè)’$’。腳本結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_27.png.jpg" alt="14_27.png.jpg" />

Shell腳本還可以和用戶交互。

http://wiki.jikexueyuan.com/project/linux/images/14_28.png.jpg" alt="14_28.png.jpg" />

這就用到了read命令了,它可以從標(biāo)準(zhǔn)輸入獲得變量的值,后跟變量名。”read x”表示x變量的值需要用戶通過(guò)鍵盤輸入得到腳本執(zhí)行過(guò)程如下:

http://wiki.jikexueyuan.com/project/linux/images/14_29.png.jpg" alt="14_29.png.jpg" />

我們不妨加上-x選項(xiàng)再來(lái)看看這個(gè)執(zhí)行過(guò)程:

http://wiki.jikexueyuan.com/project/linux/images/14_44.png.jpg" alt="14_44.png.jpg" />

test4.sh中還有更加簡(jiǎn)潔的方式。

http://wiki.jikexueyuan.com/project/linux/images/14_45.png.jpg" alt="14_45.png.jpg" />

read -p 選項(xiàng)類似echo的作用執(zhí)行如下:

http://wiki.jikexueyuan.com/project/linux/images/14_46.png.jpg" alt="14_46.png.jpg" />

你有沒(méi)有用過(guò)這樣的命令”/etc/init.d/iptables restart “ 前面的/etc/init.d/iptables 文件其實(shí)就是一個(gè)shell腳本,為什么后面可以跟一個(gè)”restart”? 這里就涉及到了shell腳本的預(yù)設(shè)變量實(shí)際上,shell腳本在執(zhí)行的時(shí)候后邊是可以跟變量的,而且還可以跟多個(gè)。不妨筆者寫一個(gè)腳本,你就會(huì)明白了

http://wiki.jikexueyuan.com/project/linux/images/14_47.png.jpg" alt="14_47.png.jpg" />

執(zhí)行過(guò)程如下:

http://wiki.jikexueyuan.com/project/linux/images/14_48.png.jpg" alt="14_48.png.jpg" />

在腳本中,你會(huì)不會(huì)奇怪,哪里來(lái)的$1$2,這其實(shí)就是shell腳本的預(yù)設(shè)變量,其中$1的值就是在執(zhí)行的時(shí)候輸入的1,而$2的值就是執(zhí)行的時(shí)候輸入的$2,當(dāng)然一個(gè)shell腳本的預(yù)設(shè)變量是沒(méi)有限制的,這回你明白了吧另外還有一個(gè)$0,不過(guò)它代表的是腳本本身的名字。不妨把腳本修改一下

http://wiki.jikexueyuan.com/project/linux/images/14_49.png.jpg" alt="14_49.png.jpg" />

執(zhí)行結(jié)果想必你也猜到了吧。

http://wiki.jikexueyuan.com/project/linux/images/14_50.png.jpg" alt="14_50.png.jpg" />

【shell腳本中的邏輯判斷

如果你學(xué)過(guò)C或者其他語(yǔ)言,相信你不會(huì)對(duì)if 陌生,在shell腳本中我們同樣可以使用if邏輯判斷。shellif判斷的基本語(yǔ)法為:

1)不帶else

if 判斷語(yǔ)句; then

command

fi

http://wiki.jikexueyuan.com/project/linux/images/14_51.png.jpg" alt="14_51.png.jpg" />

if1.sh中出現(xiàn)了 ((a<60))這樣的形式,這是shell腳本中特有的格式,用一個(gè)小括號(hào)或者不用都會(huì)報(bào)錯(cuò),請(qǐng)記住這個(gè)格式,即可執(zhí)行結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_52.png.jpg" alt="14_52.png.jpg" />

2)帶有else

if 判斷語(yǔ)句 ; then

command

else

command

fi

http://wiki.jikexueyuan.com/project/linux/images/14_53.png.jpg" alt="14_53.png.jpg" />

執(zhí)行結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_54.png.jpg" alt="14_54.png.jpg" />

3)帶有elif

if 判斷語(yǔ)句一 ; then

command

elif 判斷語(yǔ)句二; then

command

else

command

fi

http://wiki.jikexueyuan.com/project/linux/images/14_55.png.jpg" alt="14_55.png.jpg" />

這里的 && 表示并且的意思,當(dāng)然你也可以使用 || 表示或者,執(zhí)行結(jié)果:

http://wiki.jikexueyuan.com/project/linux/images/14_56.png.jpg" alt="14_56.png.jpg" />

以上只是簡(jiǎn)單的介紹了if語(yǔ)句的結(jié)構(gòu)。在判斷數(shù)值大小除了可以用”(( ))”的形式外,還可以使用”[ ]”。但是就不能使用>, < , = 這樣的符號(hào)了,要使用 -lt (小于),-gt (大于),-le (小于等于),-ge (大于等于),-eq (等于),-ne (不等于)。

http://wiki.jikexueyuan.com/project/linux/images/14_57.png.jpg" alt="14_57.png.jpg" />

再看看if中使用 && ||的情況

http://wiki.jikexueyuan.com/project/linux/images/14_71.png.jpg" alt="14_71.png.jpg" />

shell 腳本中if還經(jīng)常判斷關(guān)于檔案屬性,比如判斷是普通文件還是目錄,判斷文件是否有讀寫執(zhí)行權(quán)限等常用的也就幾個(gè)選項(xiàng):

-e :判斷文件或目錄是否存在

-d :判斷是不是目錄,并是否存在

-f :判斷是否是普通文件,并存在

-r :判斷文檔是否有讀權(quán)限

-w :判斷是否有寫權(quán)限

-x :判斷是否可執(zhí)行

使用if判斷時(shí),具體格式為: if [ -e filename ] ; then

http://wiki.jikexueyuan.com/project/linux/images/14_72.png.jpg" alt="14_72.png.jpg" />

shell 腳本中,除了用if來(lái)判斷邏輯外,還有一種常用的方式,那就是case具體格式為:

case 變量 in

value1)

command

;;

value2)

command

;;

value3)

command

;;

*)

command

;;

esac

上面的結(jié)構(gòu)中,不限制value的個(gè)數(shù),*則代表除了上面的value外的其他值。下面筆者寫一個(gè)判斷輸入數(shù)值是奇數(shù)或者偶數(shù)的腳本。

http://wiki.jikexueyuan.com/project/linux/images/14_73.png.jpg" alt="14_73.png.jpg" />

$a 的值或?yàn)?/span>1或?yàn)?/span>0,執(zhí)行結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_74.png.jpg" alt="14_74.png.jpg" />

也可以看一下執(zhí)行過(guò)程:

http://wiki.jikexueyuan.com/project/linux/images/14_75.png.jpg" alt="14_75.png.jpg" />

case腳本常用于編寫系統(tǒng)服務(wù)的啟動(dòng)腳本,例如/etc/init.d/iptables中就用到了,你不妨去查看一下

【shell腳本中的循環(huán)

Shell腳本中也算是一門簡(jiǎn)易的編程語(yǔ)言了,當(dāng)然循環(huán)是不能缺少的。常用到的循環(huán)有for循環(huán)和while循環(huán)下面就分別介紹一下兩種循環(huán)的結(jié)構(gòu)。

http://wiki.jikexueyuan.com/project/linux/images/14_76.png.jpg" alt="14_76.png.jpg" />

腳本中的seq 1 5 表示從15的一個(gè)序列。你可以直接運(yùn)行這個(gè)命令試下。腳本執(zhí)行結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_77.png.jpg" alt="14_77.png.jpg" />

通過(guò)這個(gè)腳本就可以看到for循環(huán)的基本結(jié)構(gòu)

for 變量名 in 循環(huán)的條件; do

command

done

http://wiki.jikexueyuan.com/project/linux/images/14_78.png.jpg" alt="14_78.png.jpg" />

循環(huán)的條件那一部分也可以寫成這樣的形式,中間用空格隔開(kāi)即可。你也可以試試,for i in ls; do echo $i; done for i in cat test.txt do echo $i; done

http://wiki.jikexueyuan.com/project/linux/images/14_79.png.jpg" alt="14_79.png.jpg" />

再來(lái)看看這個(gè)while循環(huán),基本格式為:

while 條件; do

command

done

腳本的執(zhí)行結(jié)果為:

http://wiki.jikexueyuan.com/project/linux/images/14_80.png.jpg" alt="14_80.png.jpg" />

另外你可以把循環(huán)條件忽略掉,筆者常常這樣寫監(jiān)控腳本

while :; do

command

done

【shell腳本中的函數(shù)

如果你學(xué)過(guò)開(kāi)發(fā),肯定知道函數(shù)的作用如果你是剛剛接觸到這個(gè)概念的話,也沒(méi)有關(guān)系,其實(shí)很好理解的。函數(shù)就是把一段代碼整理到了一個(gè)小單元中,并給這個(gè)小單元起一個(gè)名字,當(dāng)用到這段代碼時(shí)直接調(diào)用這個(gè)小單元的名字即可。有時(shí)候腳本中的某段代總是重復(fù)使用,如果寫成函數(shù),每次用到時(shí)直接用函數(shù)名代替即可,這樣就節(jié)省了時(shí)間還節(jié)省了空間。

http://wiki.jikexueyuan.com/project/linux/images/14_81.png.jpg" alt="14_81.png.jpg" />

fun.sh 中的sum() 為自定義的函數(shù),在shell腳本中要用

function 函數(shù)名() {

command

}

這樣的格式去定義函數(shù)。

上個(gè)腳本執(zhí)行過(guò)程如下:

http://wiki.jikexueyuan.com/project/linux/images/14_82.png.jpg" alt="14_82.png.jpg" />

有一點(diǎn)筆者要提醒你一下,在shell腳本中,函數(shù)一定要寫在最前面,不能出現(xiàn)在中間或者最后,因?yàn)楹瘮?shù)是要被調(diào)用的,如果還沒(méi)有出現(xiàn)就被調(diào)用,肯定是會(huì)出錯(cuò)的。

Shell腳本大體上就介紹這么多了,筆者所舉的例子都是最基礎(chǔ)的,所以即使你把所有例子完全掌握也不代表你的shell腳本編寫能力有多么好。所以剩下的日子里你盡量要多練習(xí),多寫腳本,你寫的腳本越多,你的能力就越強(qiáng)。希望你能夠找專門介紹shell腳本的書籍深入的去研究一下它。隨后筆者將給你留幾個(gè)shell腳本的練習(xí)題,你最好不要偷懶。

1. 編寫shell腳本,計(jì)算1-100的和;

2. 編寫shell腳本,要求輸入一個(gè)數(shù)字,然后計(jì)算出從1到輸入數(shù)字的和,要求,如果輸入的數(shù)字小于1,則重新輸入,直到輸入正確的數(shù)字為止;

3. 編寫shell腳本,把/root/目錄下的所有目錄(只需要一級(jí))拷貝到/tmp/目錄下;

4. 編寫shell腳本,批量建立用戶user_00, user_01, … ,user_100并且所有用戶同屬于users組;

5. 編寫shell腳本,截取文件test.log中包含關(guān)鍵詞’abc’的行中的第一列(假設(shè)分隔符為”:”),然后把截取的數(shù)字排序(假設(shè)第一列為數(shù)字),然后打印出重復(fù)次數(shù)超過(guò)10次的列;

6. 編寫shell腳本,判斷輸入的IP是否正確(IP的規(guī)則是,n1.n2.n3.n4,其中1<n1<255, 0<n2<255, 0<n3<255, 0<n4<255。

以下為練習(xí)題答案:

1. #! /bin/bash

sum=0

for i in seq 1 100; do

sum=$[$i+$sum]

done

echo $sum

2. #! /bin/bash

n=0

while [ $n -lt "1" ]; do

read -p "Please input a number, it must greater than "1":" n

done

?

sum=0

for i in seq 1 $n; do

sum=$[$i+$sum]

done

echo $sum

?

3. #! /bin/bash

for f in ls /root/; do

if [ -d $f ] ; then

cp -r $f /tmp/

fi

done

?

4. #! /bin/bash

groupadd users

for i in seq 0 9; do

useradd -g users user_0$i

done

?

for j in seq 10 100; do

useradd -g users user_$j

done

?

5. #! /bin/bash

awk -F':' '$0~/abc/ ' test.log >/tmp/n.txt

sort -n n.txt |uniq -c |sort -n >/tmp/n2.txt

awk '$1>10 ' /tmp/n2.txt

?

6. #! /bin/bash

checkip() {

if echo $1 |egrep -q '^[0-9].[0-9].[0-9].[0-9]/span> ; then

a=echo $1 | awk -F. ''

b=echo $1 | awk -F. ''

c=echo $1 | awk -F. ''

d=echo $1 | awk -F. ''

?

for n in $a $b $c $d; do

if [ $n -ge 255 ] || [ $n -le 0 ]; then

echo "the number of the IP should less than 255 and greate than 0"

return 2

fi

done

else

echo "The IP you input is something wrong, the format is like 192.168.100.1"

return 1

fi

}

?

rs=1

while [ $rs -gt 0 ]; do

read -p "Please input the ip:" ip

checkip $ip

rs=echo $?

done

echo "The IP is right!"