終於到shell 腳本這章了,在之前筆者賣了好多關子說shell腳本怎麼怎麼重要,確實shell腳本在linux系統管理員的運維工做中很是很是重要。下面筆者就帶你正式進入shell腳本的世界吧。linux
到如今爲止,你明白什麼是shell腳本嗎?若是明白最好了,不明白也沒有關係,相信隨着學習的深刻你就會愈來愈瞭解到底什麼是shell腳本。首先它是一個腳本,並不能做爲正式的編程語言。由於是跑在linux的shell中,因此叫shell腳本。說白了,shell腳本就是一些命令的集合。舉個例子,我想實現這樣的操做:1)進入到/tmp/目錄;2)列出當前目錄中全部的文件名;3)把全部當前的文件拷貝到/root/目錄下;4)刪除當前目錄下全部的文件。簡單的4步在shell窗口中須要你敲4次命令,按4次回車。這樣是否是很麻煩?固然這4步操做很是簡單,若是是更加複雜的命令設置須要幾十次操做呢?那樣的話一次一次敲鍵盤會很麻煩。因此不妨把全部的操做都記錄到一個文檔中,而後去調用文檔中的命令,這樣一步操做就能夠完成。其實這個文檔呢就是shell腳本了,只是這個shell腳本有它特殊的格式。web
Shell腳本能幫助咱們很方便的去管理服務器,由於咱們能夠指定一個任務計劃定時去執行某一個shell腳本實現咱們想要需求。這對於linux系統管理員來講是一件很是值得自豪的事情。如今的139郵箱很好用,發郵件的同時還能夠發一條郵件通知的短信給用戶,利用這點,咱們就能夠在咱們的linux服務器上部署監控的shell腳本,好比網卡流量有異常了或者服務器web服務器中止了就能夠發一封郵件給管理員,同時發送給管理員一個報警短信這樣可讓咱們及時的知道服務器出問題了。shell
有一個問題須要約定一下,凡是自定義的腳本建議放到/usr/local/sbin/目錄下,這樣作的目的是,一來能夠更好的管理文檔;二來之後接管你的管理員都知道自定義腳本放在哪裏,方便維護。編程
【shell腳本的基本結構以及如何執行】vim
Shell腳本一般都是以.sh 爲後綴名的,這個並非說不帶.sh這個腳本就不能執行,只是你們的一個習慣而已。因此,之後你發現了.sh爲後綴的文件那麼它必定會是一個shell腳本了。test.sh中第一行必定是 「#! /bin/bash」 它表明的意思是,該文件使用的是bash語法。若是不設置該行,那麼你的shell腳本就不能被執行。’#’表示註釋,在前面講過的。後面跟一些該腳本的相關注釋內容以及做者和建立日期或者版本等等。固然這些註釋並不是必須的,若是你懶的很,能夠省略掉,可是筆者不建議省略。由於隨着你工做時間的增長,你寫的shell腳本也會愈來愈多,若是有一天你回頭查看你寫的某個腳本時,頗有可能忘記該腳本是用來幹什麼的以及何時寫的。因此寫上註釋是有必要的。另外系統管理員並不是你一個,若是是其餘管理員查看你的腳本,他看不懂豈不是很鬱悶。該腳本再往下面則爲要運行的命令了。bash
Shell腳本的執行很簡單,直接」sh filename 「 便可,另外你還能夠這樣執行服務器
默認咱們用vim編輯的文檔是不帶有執行權限的,因此須要加一個執行權限,那樣就能夠直接使用’./filename’ 執行這個腳本了。另外使用sh命令去執行一個shell腳本的時候是能夠加-x選項來查看這個腳本執行過程的,這樣有利於咱們調試這個腳本哪裏出了問題。less
該shell腳本中用到了’date’這個命令,它的做用就是用來打印當前系統的時間。其實在shell腳本中date使用率很是高。有幾個選項筆者經常在shell腳本中用到:運維
%Y表示年,%m表示月,%d表示日期,%H表示小時,%M表示分鐘,%S表示秒編程語言
注意%y和%Y的區別。
-d 選項也是常常要用到的,它能夠打印n天前或者n天后的日期,固然也能夠打印n個月/年前或者後的日期。
另外星期幾也是經常使用的
【shell腳本中的變量】
在shell腳本中使用變量顯得咱們的腳本更加專業更像是一門語言,開個玩笑,變量的做用固然不是爲了專業。若是你寫了一個長達1000行的shell腳本,而且腳本中出現了某一個命令或者路徑幾百次。忽然你以爲路徑不對想換一下,那豈不是要更改幾百次?你當然可使用批量替換的命令,可是也是很麻煩,而且腳本顯得臃腫了不少。變量的做用就是用來解決這個問題的。
在test2.sh中使用到了反引號,你是否還記得它的做用?’d’和’d1’在腳本中做爲變量出現,定義變量的格式爲 「變量名=變量的值」。當在腳本中引用變量時須要加上’$’符號,這跟前面講的在shell中自定義變量是一致的。下面看看腳本執行結果吧。
下面咱們用shell計算兩個數的和。
數學計算要用’[ ]’括起來而且外頭要帶一個’$’。腳本結果爲:
Shell腳本還能夠和用戶交互。
這就用到了read命令了,它能夠從標準輸入得到變量的值,後跟變量名。」read x」表示x變量的值須要用戶經過鍵盤輸入獲得。腳本執行過程以下:
咱們不妨加上-x選項再來看看這個執行過程:
在test4.sh中還有更加簡潔的方式。
read -p 選項相似echo的做用。執行以下:
你有沒有用過這樣的命令」/etc/init.d/iptables restart 「 前面的/etc/init.d/iptables 文件其實就是一個shell腳本,爲何後面能夠跟一個」restart」? 這裏就涉及到了shell腳本的預設變量。實際上,shell腳本在執行的時候後邊是能夠跟變量的,並且還能夠跟多個。不妨筆者寫一個腳本,你就會明白了。
執行過程以下:
在腳本中,你會不會奇怪,哪裏來的$1和$2,這其實就是shell腳本的預設變量,其中$1的值就是在執行的時候輸入的1,而$2的值就是執行的時候輸入的$2,固然一個shell腳本的預設變量是沒有限制的,這回你明白了吧。另外還有一個$0,不過它表明的是腳本自己的名字。不妨把腳本修改一下。
執行結果想必你也猜到了吧。
【shell腳本中的邏輯判斷】
若是你學過C或者其餘語言,相信你不會對if 陌生,在shell腳本中咱們一樣可使用if邏輯判斷。在shell中if判斷的基本語法爲:
1)不帶else
if 判斷語句; then
command
fi
在if1.sh中出現了 ((a<60))這樣的形式,這是shell腳本中特有的格式,用一個小括號或者不用都會報錯,請記住這個格式,便可。執行結果爲:
2)帶有else
if 判斷語句 ; then
command
else
command
fi
執行結果爲:
3)帶有elif
if 判斷語句一 ; then
command
elif 判斷語句二; then
command
else
command
fi
這裏的 && 表示「而且」的意思,固然你也可使用 || 表示「或者」,執行結果:
以上只是簡單的介紹了if語句的結構。在判斷數值大小除了能夠用」(( ))」的形式外,還可使用」[ ]」。可是就不能使用>, < , = 這樣的符號了,要使用 -lt (小於),-gt (大於),-le (小於等於),-ge (大於等於),-eq (等於),-ne (不等於)。
再看看if中使用 && 和 ||的狀況。
shell 腳本中if還常常判斷關於檔案屬性,好比判斷是普通文件仍是目錄,判斷文件是否有讀寫執行權限等。經常使用的也就幾個選項:
-e :判斷文件或目錄是否存在
-d :判斷是否是目錄,並是否存在
-f :判斷是不是普通文件,並存在
-r :判斷文檔是否有讀權限
-w :判斷是否有寫權限
-x :判斷是否可執行
使用if判斷時,具體格式爲: if [ -e filename ] ; then
在shell 腳本中,除了用if來判斷邏輯外,還有一種經常使用的方式,那就是case了。具體格式爲:
case 變量 in
value1)
command
;;
value2)
command
;;
value3)
command
;;
*)
command
;;
esac
上面的結構中,不限制value的個數,*則表明除了上面的value外的其餘值。下面筆者寫一個判斷輸入數值是奇數或者偶數的腳本。
$a 的值或爲1或爲0,執行結果爲:
也能夠看一下執行過程:
case腳本經常使用於編寫系統服務的啓動腳本,例如/etc/init.d/iptables中就用到了,你不妨去查看一下。
【shell腳本中的循環】
Shell腳本中也算是一門簡易的編程語言了,固然循環是不能缺乏的。經常使用到的循環有for循環和while循環。下面就分別介紹一下兩種循環的結構。
腳本中的seq 1 5 表示從1到5的一個序列。你能夠直接運行這個命令試下。腳本執行結果爲:
經過這個腳本就能夠看到for循環的基本結構:
for 變量名 in 循環的條件; do
command
done
循環的條件那一部分也能夠寫成這樣的形式,中間用空格隔開便可。你也能夠試試,for i in `ls`; do echo $i; done 和 for i in `cat test.txt`; do echo $i; done
再來看看這個while循環,基本格式爲:
while 條件; do
command
done
腳本的執行結果爲:
另外你能夠把循環條件忽略掉,筆者經常這樣寫監控腳本。
while :; do
command
done
【shell腳本中的函數】
若是你學過開發,確定知道函數的做用。若是你是剛剛接觸到這個概念的話,也沒有關係,其實很好理解的。函數就是把一段代碼整理到了一個小單元中,並給這個小單元起一個名字,當用到這段代碼時直接調用這個小單元的名字便可。有時候腳本中的某段代老是重複使用,若是寫成函數,每次用到時直接用函數名代替便可,這樣就節省了時間還節省了空間。
fun.sh 中的sum() 爲自定義的函數,在shell腳本中要用
function 函數名() {
command
}
這樣的格式去定義函數。
上個腳本執行過程以下:
有一點筆者要提醒你一下,在shell腳本中,函數必定要寫在最前面,不能出如今中間或者最後,由於函數是要被調用的,若是尚未出現就被調用,確定是會出錯的。
Shell腳本大致上就介紹這麼多了,筆者所舉的例子都是最基礎的,因此即便你把全部例子徹底掌握也不表明你的shell腳本編寫能力有多麼好。因此剩下的日子裏你儘可能要多練習,多寫腳本,你寫的腳本越多,你的能力就越強。但願你可以找專門介紹shell腳本的書籍深刻的去研究一下它。隨後筆者將給你留幾個shell腳本的練習題,你最好不要偷懶。
1. 編寫shell腳本,計算1-100的和;
2. 編寫shell腳本,要求輸入一個數字,而後計算出從1到輸入數字的和,要求,若是輸入的數字小於1,則從新輸入,直到輸入正確的數字爲止;
3. 編寫shell腳本,把/root/目錄下的全部目錄(只須要一級)拷貝到/tmp/目錄下;
4. 編寫shell腳本,批量創建用戶user_00, user_01, … ,user_100而且全部用戶同屬於users組;
5. 編寫shell腳本,截取文件test.log中包含關鍵詞’abc’的行中的第一列(假設分隔符爲」:」),而後把截取的數字排序(假設第一列爲數字),而後打印出重複次數超過10次的列;
6. 編寫shell腳本,判斷輸入的IP是否正確(IP的規則是,n1.n2.n3.n4,其中1<n1<255, 0<n2<255,="" 0<n3<255,="" 0<n4<255<="" span="">)。
如下爲練習題答案:
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/ {print $1}' test.log >/tmp/n.txt
sort -n n.txt |uniq -c |sort -n >/tmp/n2.txt
awk '$1>10 {print $2}' /tmp/n2.txt
6. #! /bin/bash
checkip() {
if echo $1 |egrep -q '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$' ; then
a=`echo $1 | awk -F. '{print $1}'`
b=`echo $1 | awk -F. '{print $2}'`
c=`echo $1 | awk -F. '{print $3}'`
d=`echo $1 | awk -F. '{print $4}'`
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!"