一、基本習慣的養成
1、腳本應該放在指定的位置
一般的,放在家目錄的scripts內;執行腳本即需執行sh sh01.sh即可,因爲sh在bash中即位於/bin下;
使用-n -x來校驗腳本的語法是否正確;
2、腳本的書寫規範
一般的,需要在頭部註明Program,Histoty,作者,時間,版本等信息
一般的,特殊的程序加上#進行註釋會對以後查詢很有幫助;
在內部程序,代碼最好能以 [tab] 按鍵的空格向後推, 這樣你的程序代碼會顯的非常的漂亮和有條理,在查閱和debug上也會很輕鬆
在主程序完成後,回傳一個值給系統進行執行結果的告知,如exit 0,執行完後回傳0給系統,此時去$?則顯示爲0,即執行成功;
二、簡單的一些例子
1、讓用戶輸入,和用戶交互
read -p "please input your fist name:" firstname #讓用戶輸入它的第一個名字,並把該值賦予變量firstname
2、數值運算
+ - * / %(這裏的%是取餘數的意思)
var=$((數值運算式))或者可以delcare -i total=$firstnu*$secnu,建議使用前一種;
3、善於運用判斷式
一般的,可以利用test命令進行測試
(1)關於文件的測試,如test -e filename
-e 該『檔名』是否存在?(常用)
-f 該『檔名』是否存在且爲檔案(file)?(常用)
-d 該『文件名』是否存在且爲目錄(directory)?(常用)
(2)關於某文件是否具有某些權限的測試,如test -r filename
-r 偵測該檔名是否存在且具有『可讀』的權限?
-w 偵測該檔名是否存在且具有『可寫』的權限?
-x 偵測該檔名是否存在且具有『可執行』的權限?
(3)關於兩個整數之間的判斷
-eq 兩數值相等 (equal)
-ne 兩數值不等 (not equal)
-gt n1 大亍 n2 (greater than)
-lt n1 小亍 n2 (less than)
-ge n1 大亍等亍 n2 (greater than or equal)
-le n1 小亍等亍 n2 (less than or equal)
(4)關於字符串的判斷
test -z string 刞定字符串是否爲 0 ?若 string 爲穸字符串,則爲 true
test -n string 刞定字符串是否非爲 0 ?若 string 爲穸字符串,則爲 false。注: -n 亦可省略
test str1 = str2 刞定 str1 是否等亍 str2 ,若相等,則回傳 true
test str1 != str2 刞定 str1 是否丌等亍 str2 ,若相等,則回傳 false
(5)多重條件判斷,如test -r filename -a -x filename
-a (and)兩狀況同時成立!例如 test -r file -a -x file,則 file 同時具有r 不 x 權限時,纔回傳 true。
-o (or)兩狀況任何一個成立!例如 test -r file -o -x file,則 file 具有 r或者 x 權限時,就可回傳 true。
! 反相狀態,如 test ! -x file ,當 file 丌具有 x 時,回傳 true
示例:讓用戶輸入文件名稱,並判斷是否存在,若不存在則報告信息,若存在則判斷其是否屬於文件or目錄,並判斷其讀寫權限;
[root@www scripts]# vi sh05.sh
#!/bin/bash
# Program:
# User input a filename, program will check the flowing:
# 1.) exist? 2.) file/directory? 3.) file permissions
# History:
# 2005/08/25 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 1. 譏使用者輸入檔名,幵且刞斷使用者是否真的有輸入字符串?
echo -e "Please input a filename, I will check the filename's type and \
permission. \n\n"
read -p "Input a filename : " filename
test -z $filename && echo "You MUST input a filename." && exit 0
# 2. 刞斷檔案是否存在?若不存在則顯示訊息並結束腳本
test ! -e $filename && echo "The filename '$filename' DO NOT exist" &&
exit 0
# 3. 開始刞斷文件類型不屬性
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
# 4. 開始輸出信息!
echo "The filename: $filename is a $filetype"
echo "And the permissions are : $perm"
4、利用[]做判斷
[]做條件判斷時一般用在if語句中。不過要注意,因爲[]在bash的特殊字符和正則表達式中均有不同的含義,因此在shell腳本中,要注意,在[]中的每一個字符都要有空格隔開,例如 [□"$HOME"□==□"$MAIL"□]
↑ ↑ ↑ ↑ #這些都是空格的意思,否則將報錯說參數(argument)過多;
5、shell腳本的默認參數$0,$1......
意思就是,對於shell腳本來說,在執行這個shell腳本(即在sh scritname)的時候,可以帶上參數$1,$2, $3...(即可以不用像read似得需要在執行的過程中輸入參數), 這樣的話就可以在shell腳本內直接使用$1,意思就是執行的時候輸入的這個變量值;對於shell腳本來說,是支持這樣做的,其默認的格式如下:
/path/to/scriptname opt1 opt2 opt3 opt4
$0 $1 $2 $3 $4 #執行的腳本即爲 $0 這個髮量,第一個接的參數就是 $1 ,所以,只要我們在script 裏面善用 $1 的話,就可以很簡單的 立即下達某些命令功能
除了這些數字的髮量之外, 我們還有一些較爲特殊的變量可以在 script 內使用來呼出這些參數
$# :代表後面接的參數『個數』,以上表爲例這裏顯示爲『 4 』;
$@ :代表『 "$1" "$2" "$3" "$4" 』之意,每個變量是獨立的(用雙引號括起來);
$* :代表『 "$1c$2c$3c$4" 』,其中 c 爲分隔字符,默認爲空格鍵, 所以本例中代表『 "$1 $2 $3 $4" 』之意。
提示: $@ 和 $* 基本上還是有所不同,不過,一般使用情況下可以直接記憶 $@ 即可!
示例:[root@www scripts]# vi sh07.sh
#!/bin/bash
# Program:
# Program shows the script name, parameters...
# History:
# 2009/02/17 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "The script name is ==> $0"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0
echo "Your whole parameter is ==> '$@'"
echo "The 1st parameter ==> $1"
echo "The 2nd parameter ==> $2"
執行結果如下:
[root@www scripts]# sh sh07.sh theone haha quot
The script name is ==> sh07.sh <==腳本名稱
Total parameter number is ==> 3 <==果然有三個參數
Your whole parameter is ==> 'theone haha quot' <==參數的內容全部
The 1st parameter ==> theone <==第一個參數
The 2nd parameter ==> haha <==第二個參數
6、條件判斷式
(1)利用if...then
a、單層,簡單條件判斷式,語法格式如下
if [ 條件刞斷式 ]; then
當條件刞斷式成立時,可以進行的指令工作內容;
fi #將 if 反過來寫,就成爲 fi 啦!結束 if 之意!
PS:除了可以將多個判斷式寫在一個[]之外,還可以寫多個[],之間用&&(表示and)或者||(表示or)鏈接起來,比如[ "$yn" == "Y" -o "$yn" == "y" ]等同於[ "$yn" == "Y" ] || [ "$yn" == "y" ]
b、多重、複雜條件判斷式,語法格式如下
if [ 條件刞斷式一 ]; then
當條件刞斷式一成立時,可以進行的指令工作內容;
elif [ 條件刞斷式二 ]; then # elif 也是個刞斷式,也有條件判斷式,因此出現 elif 後面都要接 then 來處理;
當條件刞斷式二成立時,可以進行的指令工作內容;
else # else是最後沒有成立的結果了,所以後面沒有 then 了;
當條件刞斷式一不二均不成立時,可以進行的指令工作內容;
fi
(2)利用case...esac判斷
if是通過比對的方式進行判斷的,而如果變量的數量有限,就可以通過case...esac來判斷,語法如下
case $髮量名稱 in #關鍵詞爲 case ,還有變量前有錢字號
"第一個髮量內容") #每個髮量內容都建議用雙引號括起來,關鍵詞則爲小括號 )
程序段
;; #每個類刪結尾使用兩個連續的分號來處理!
"第二個髮量內容")
程序段
;;
*) #最後一個髮量內容都會用 * 來代表所有其他值,不包含第一個髮量內容與第二個髮量內容的其他程序執行段
exit 1
;;
esac #最終的 case 結尾!『反過來寫』思考一下!
示例:case $1 in
"one")
echo "Your choice is ONE"
;;
"two")
echo "Your choice is TWO"
;;
"three")
echo "Your choice is THREE"
;;
*)
echo "Usage $0 {one|two|three}" #若用戶輸入其他的變量,則提示只能使用這三個變量
;;
esac
(3)利用function功能
即在腳本中自定義一個功能,後面可以進行調用,如上面的例子,因爲都是同一個動作,則可以定義一個function,語法如下:
function fname() { #這個 fname 就是要定義的function的名稱 ,程序段就是要它執行的功能;注意,一般的要寫在腳本的最前面;
程序段
}
示例:function printit(){
echo -n "Your choice is " # 加上 -n 可以丌斷行繼續在同一行顯示
}
echo "This program will print your selection !"
case $1 in
"one")
printit; echo $1 | tr 'a-z' 'A-Z' # 將參數做大小寫轉換,並注意這裏函數名稱後面有一個;
;;
"two")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
"three")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac
說明:unction 也是擁有內建變量的,他的內建變量和 shell script 很類似, 函數名稱代表示 $0 ,而後續接的變量也是以 $1, $2... 來定義的。 這裏很容易搞錯,因爲『 function fname() { 程序段 } 』內的 $0, $1... 等等與 shell script 的 $0 是不同的。以上面 sh12-2.sh 來說,假如我下達:『 sh sh12-2.sh one 』 這表示在 shell script 內的 $1 爲 "one" 這個字符串。但是在 printit() 內的 $1 則與這個 one 無關
(4)循環語句
循環可以不斷的執行某個程序段,直到用戶定義的條件達成位爲止,所以重點是哪個程序的達成條件是什麼。除了這種依靠判斷式是否達成的不定循環之外,還有一種已經固定要跑多少次的循環狀態。
a、while do done語句,意思是當 condition 條件成立時,就進行循環,直到condition 的條件不成立才停止
while [ condition ] #中括號內的狀態就是刞斷式
do #do 是循環的開始!
程序段落
done #done 是循環的結束
b、unitl do done語句,意思恰恰和while 相反,它說的是『當 condition 條件成立時,就終止循環, 否則就持續進行循環程序段(可知,until爲真時,就直接跳過程序段)。
until [ condition ]
do
程序段落
done
c、for do done語句,for 這種語法,則是『 已經知道要進行幾次循環』的狀態!語法爲
for var in con1 con2 con3 ...
do
程序段
done
說明:以上面的例子來說,這個 $var 的髮量內容在循環工作時:1. 第一次循環時, $var 的內容爲 con1 ; 2. 第二次循環時, $var 的內容爲 con2 ;3. 第三次循環時, $var 的內容爲 con3 ; 4. ....
示例1:network="192.168.1" # 先定義一個網域的前面部分!
for sitenu in $(seq 1 100) # seq 爲 sequence(連續) 的縮寫之意
do
# 底下的程序在叏得 ping 的回傳值是正確的還是失敗的!
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
# 開始顯示結果是正確的吪勱 (UP) 還是錯誤的沒有連通 (DOWN)
if [ "$result" == 0 ]; then
echo "Server ${network}.${sitenu} is UP."
else
echo "Server ${network}.${sitenu} is DOWN."
fi
done
示例2:read -p "Please input a directory: " dir
if [ "$dir" == "" -o ! -d "$dir" ]; then
echo "The $dir is NOT exist in your system."
exit 1
fi
# 開始測試檔案囉~
filelist=$(ls $dir) # 列出所有在該目錄下的文件名
for filename in $filelist
do
perm=""
test -r "$dir/$filename" && perm="$perm readable"
test -w "$dir/$filename" && perm="$perm writable"
test -x "$dir/$filename" && perm="$perm executable"
echo "The file $dir/$filename's permission is $perm "
done
d、for do done的數值處理
除了上述之外,for done的另外一種寫法爲
for (( 初始值; 限制值; 執行步階 ))
do
程序段
done
說明:這種語法適合於數值方式的運算當中,在 for 後面的括號內的三串內容意爲:
初始值:某個變量在循環當中的起始值,直接以類似 i=1 設定好;
限制值:當變量的值在這個限制值的範圍內,就繼續進行循環。例如 i<=100;
執行步階:每作一次循環時,變量的發化量。例如 i=i+1(如果每次增加 1 ,則可以使用類似『i++』)
示例:read -p "Please input a number, I will count for 1+2+...+your_input: " nu
s=0
for (( i=1; i<=$nu; i=i+1 ))
do
s=$(($s+$i))
done
echo "The result of '1+2+3+...+$nu' is ==> $s"
三、腳本的測試及debug
sh [-nvx] scripts.sh
參數說明:
-n :不要執行 script,僅查詢語法的問題;
-v :再執行 sccript 前,先將 scripts 的內容輸出到屏幕上;
-x :將使用到的 script 內容顯示到屏幕上,這是很有用的參數,因爲顯示的都是指令,可以知道是哪個指令發生錯誤了。
腳本的學習,多看、多模仿、幵加以修改成自己的樣式!』 是最塊的學習手段了!網上有相當多的有用的 scripts ,可以將對方的 scripts 拿來,幵且改成適合自己主機的樣子!另外,我們 Linux 系統本來就有很多的服務啓動腳本, 可以直接以 vim 進入該 script 去查閱一下,通常立刻就知道該 script 的目的。