shell script 能夠將Linux 指令集合在一起,
不只能夠做計算、檔案讀寫,還可以自動操作、定期檢查Linux作業系統,
是作業系統、伺服器的管理的工程師所需具備的能力。
linux shell script 基本教學連結如下(本教學使用之環境之bash shell):
shell script 能夠將Linux 指令集合在一起,
不只能夠做計算、檔案讀寫,還可以自動操作、定期檢查Linux作業系統,
是作業系統、伺服器的管理的工程師所需具備的能力。
linux shell script 基本教學連結如下(本教學使用之環境之bash shell):
函式
語法為:
function 函式名稱()
{ 函式程式碼 }
在函式程式碼中,可用:
(1) $N來擷取第N個參數的值(N是整數,從1開始)。
(2) $#可用來擷取參數的數目。
(3) $*可擷取所有輸入參數。
(4) shift指令可以解除第一個參數的設定,並使所有參數「往前靠攏」。此時$N的值會被原本$N+1的值所取代,$#的值也會減1,$*也會改變。
範例如:
function get_mean()
{
t=0
n=$#
echo "the mean of "$*":"
while [ $# -ne 0 ]
do
t=$(($t+$1))
shift
done
t=$(($t/n))
echo $t
}
get_mean 1 6 10 32
執行後顯示:
注意:shell script中並不支援浮點數,故除法所算出的結果,會四捨五入成整數。
※註(極重要!):事實上,在shell script中「非函式程式碼」的部分,$N、$#、$*、shift也有意義。此時$N代表的是「script 參數變數」而非「函式參數變數」。這也說明了,在執行shell script程式的時候可以輸入參數,如這樣的命令:
sh 檔案名稱.sh 參數一 參數二 #參數可以有任意個或者是沒有
將之前的例子修改一下,現有一個名為tt.sh的shell script程式,其程式碼為:
t=0
n=$#
echo "the mean of "$*":"
while [ $# -ne 0 ]
do
t=$(($t+$1))
shift
done
t=$(($t/n))
echo $t #這程式碼只是把之前例子中,function裡的程式碼給拿出來而已
我們在命令列執行shell script程式時可以輸入參數,如:sh tt.sh 10 90 22 101 30
執行結果顯示:
這就是「script 參數變數」的效果!
判斷式與迴圈(loop):
(1) while迴圈:
其語法架構為:
while [ 判斷式一 ] 邏輯運算符號 [ 判斷式二 ] 邏輯運算符號 [ 判斷式三 ]
do
當判斷式串的總測試結果為真,就執行寫在此的程式碼
done
說明:
※ 邏輯運算符號,可以是&&或 ||。在中括號之中,&&代表交集,||代表聯集。
※ [ 判斷式 ]與邏輯運算符號可以有無限組或只有一個[ 判斷式 ],不限於上例之三組。
※ [ 判斷式 ]中,判斷式即是3.所介紹過的判斷式。而判斷式與左右中括號之間,一定各要相隔一個空白字元,否則執行會出錯。
範例如:
i=3
while [ $i -gt 0 ] && [ $i -lt 5 ]
do
echo $i
i=$(($i-1))
done
執行顯示:
(2) until 迴圈:
其語法架構為:
until [ 判斷式一 ] 邏輯運算符號 [ 判斷式二 ] 邏輯運算符號 [ 判斷式三 ]
do
當判斷式串的總測試結果為假,就執行寫在此的程式碼。直到總測試結果為真為止。
done
說明:
※ 邏輯運算符號,可以是&&或 ||。在中括號之中,&&代表交集,||代表聯集。
※ [ 判斷式 ]與邏輯運算符號可以有無限組或只有一個[ 判斷式 ],不限於上例之三組。
※ [ 判斷式 ]中,判斷式即是3.所介紹過的判斷式。而判斷式與左右中括號之間,一定各要相隔一個空白字元,否則執行會出錯。
範例如:
i=7
until [ $i -gt 0 ] && [ $i -lt 5 ]
do
echo $i
i=$(($i-1))
done
執行顯示:
(3) for 迴圈:
for迴圈有兩種寫法:
(3-1) for 迴圈第一種寫法:
for 變數名稱 in 值一 值二 值三 #事實上,值可以有任意個
do
程式碼
done
在執行第N次迴圈(N<=值的數目)時,會將值存入變數並且執行程式碼。如:
for dirname in kkk jjj ggg
do
mkdir $dirname
done
執行之後,目錄下就多了kkk jjj ggg三個子目錄。
(3-2) for迴圈的第二種寫法,與C++中的for迴圈很像,是利用整數變數來設定初始值、迴圈執行條件、迴圈步階。語法如:
for ((變數名稱=初始值 ; 迴圈執行條件 ; 迴圈步階))
do
程式碼
done
其中,迴圈執行條件支援<、>、<=、>=符號來代表小於、大於、小於等於、大於等於,迴圈步階支援用 整數變數名稱++、整數變數名-- 來代表遞增和遞減。例如:
j=1
for ((i=1;i<=5;i++))
do
j=$(($i*$j))
done
echo $j
執行顯示:
(1) 用if…fi來測試判斷式:
(1-1) 其基本架構的寫法為:
if [ 判斷式一 ] 邏輯運算符號 [ 判斷式二 ] 邏輯運算符號 [ 判斷式三 ];
then
上述之判斷式串的最終結果若成立,就執行的寫在此命令
elif [ 判斷式甲 ] 邏輯運算符號 [ 判斷式乙 ] 邏輯運算符號 [ 判斷式丙 ];
then
第一個判斷式串最終結果為不成立,而第二的判斷式串最終結果成立,就執行的寫在此命令
else
所有判斷式串均不成立時,就執行的寫在此命令
fi
說明:
※ 邏輯運算符號,可以是&&或 ||。在中括號之中,&&代表交集,||代表聯集。
※ [ 判斷式 ]與邏輯運算符號可以有無限組或只有一個[ 判斷式 ],不限於上例之三組。
※ [ 判斷式 ]中,判斷式即是3.所介紹過的判斷式。而判斷式與左右中括號之間,一定各要相隔一個空白字元,否則執行會出錯。
※ elif 相當於C++中的 else if。
※ fi 為 if的倒反,表示if判斷式語所執行命令的結束。
(1-2) 範例如:
read -p "input n1:" n1
read -p "input n2:" n2
if [ $n1 -gt $n2 ] ;
then
echo "n1 is greater"
elif [ $n2 -gt $n1 ];
then
echo "n2 is greater"
else
echo "n1 equal to n2"
fi
執行後,n1輸入5,n2輸入10,顯示:
(2) 用case…esac來判斷:
(2-1) 其基本架構的寫法為:
case $變數名稱 in
值一)
若變數的值等於值一,就執行寫在此的命令
;;
值二)
若變數的值等於值二,就執行寫在此的命令
;;
*)
若變數的值不等於上述所有情況,就執行寫在此的命令
;;
esac
說明:
※ 對變數之值的測試可以有無限個,不限於上述之兩個。
※ 注意:每一段執行命令後面,必有兩個分號 ;;。
(2-2)範例:
read -p "do you want to go swimming? yes or no?" reply
case $reply in
"yes")
echo "OK, let's go!"
;;
"no")
echo "oh! perhaps another day."
;;
*)
echo "sorry? what are you talking about?"
;;
esac
執行後輸入 yes,顯示結果如:
判斷式:
判斷式,其判斷結果有「成立」與「不成立」兩種。可用test關鍵字來測試判斷式成立與否。這行命令:test 判斷式,和其他的命令一樣,執行後會回傳錯誤碼。※ 若判斷式成立,則錯誤碼為0,我們稱「測試結果為真」。
※ 若判斷式不成立,則錯誤碼為一個大於0的整數,我們稱「測試結果為假」。
判斷式的語法形式依據所要判斷的對象而不同。判斷式的語法形式如下:
(1) 所要判斷的對象是「路徑上的檔案」:
※ -e 路徑 :測試該路徑上是否已存在?若有則判斷式成立。
※ -f 路徑 :測試該路徑上是否已存在且其類型為檔案?若是則判斷式成立。
※ -d 路徑 :測試該路徑上是否已存在且其類型為目錄(資料夾)?若是則判斷式成立。
※ -b 路徑 :測試該路徑上是否已存在且其類型為block device 裝置?若是則判斷式成立。
※ -c 路徑 :測試該路徑上是否已存在且其類型為character device 裝置?若是則判斷式成立。
※ -S 路徑 :測試該路徑上是否已存在且其類型為Socket檔案?若是則判斷式成立。
※ -p 路徑 :測試該路徑上是否已存在且其類型為FIFO(pipe)檔案?若是則判斷式成立。
※ -L 路徑 :測試該路徑上是否已存在且其類型為連結檔?若是則判斷式成立。
(2) 所要判斷的對象是「路徑上檔案或目錄的權限或屬性」
※ -r 路徑 :測試該路徑上者,其是否具有可讀權限?若是則判斷式成立。
※ -w 路徑 :測試該路徑上者,其是否具有可寫權限?若是則判斷式成立。
※ -x 路徑 :測試該路徑上者,其是否具有可執行權限?若是則判斷式成立。
※ -u 路徑 :測試該路徑上者,其是否具有SUID屬性?若是則判斷式成立。
※ -g 路徑 :測試該路徑上者,其是否具有SGID屬性?若是則判斷式成立。
※ -k 路徑 :測試該路徑上者,其是否具有Sticky bit屬性?若是則判斷式成立。
※ -s 路徑 :測試該路徑上者,其大小是否不為零?若不為零則判斷式成立。
(3) 所要判斷的對象是「路徑上檔案或資料夾之間的比較」
※ 路徑一 -nt 路徑二 :測試路徑一上的檔案(或資料夾)是否比路徑二上的檔案(或資料夾)還要新,若是則判斷式成立。
※ 路徑一 -ot 路徑二 :測試路徑一上的檔案(或資料夾)是否比路徑二上的檔案(或資料夾)還要舊,若是則判斷式成立。
※ 路徑一 -ef 路徑二 :測試路徑一上的檔案(或資料夾)是否和路徑二上的檔案(或資料夾)指向同一個inode,若是則判斷式成立。
(4) 所要判斷的對象是「整數之間的比較」
※ $整數一 -eq $整數二:測試兩整數是否相等,若是則判斷式成立。
※ $整數一 -ne $整數二:測試兩整數是否不相等,若是則判斷式成立。
※ $整數一 -gt $整數二:測試整數一是否大於整數二,若是則判斷式成立。
※ $整數一 -lt $整數二:測試整數一是否小於整數二,若是則判斷式成立。
※ $整數一 -ge $整數二:測試整數一是否大於等於整數二,若是則判斷式成立。
※ $整數一 -le $整數二:測試整數一是否小於等於整數二,若是則判斷式成立。
(5) 所要判斷的對象是「字串的比較與判定」
※ –z $字串:測試字串是否為空字串,若是則判斷式成立。
※ –n $字串:測試字串是否為非空字串,若是則判斷式成立。
※ $字串一=$字串二:測試字串一是否等於字串二,若是則判斷式成立。
※ $字串一!== $字串二:測試字串一是否不等於字串二,若是則判斷式成立。
註(重要!):在取字串的值時,若是用$字串名稱來取值,字串內容會直接被印出來。如:
s1="sss fff"
test $s1 == "sss fff" && echo "Y" || echo "N" #關於&&和||的用法,在(6)有說明
執行結果顯示:
出現了錯誤訊息,說test命令有太多參數。事實上,第二行的寫法等同於test sss fff == "sss fff" && echo "Y" || echo "N"(因為字串s1直接被印出來了),於是Linux將sss和fff看成兩個不同的參數!造成了非預期的結果!
正確的寫法,應用"$字串名稱"來取值,如:
s1="sss fff"
test "$s1" == "sss fff" && echo "Y" || echo "N" #$s1改成了"$s1"
執行結果顯示:
,這即是預期中的結果。
結論:在對字串取值的時候,以"$字串名稱"的用法為佳。
(6) 用test測試結果的真假,可以決定要執行的命令。寫法為:
test判斷式 && 測試結果為真時要執行的命令 || 測試結果為假時要執行的命令
如:
n1=100
n2=15
test $n1 -gt $n2 && echo "n1 is greater" || echo "n2 is greater"
執行顯示:
(7) 利用test測試多重判斷式(判斷式串):
※ 判斷式的交集:判斷式一 –a 判斷式二 –a 判斷式三…:
只有當所有判斷式都成立,最終判斷結果才成立。如:
s1="dkkk"
s2="kkk"
test "$s1" == "dkkk" -a "$s2" == "kkk" && echo "Y" || echo "N"
執行顯示:
※ 判斷式的聯集:判斷式一 –o 判斷式二 –o 判斷式三…:
只要有一個判斷式都成立,最終判斷結果就成立。
※ 判斷式的反值:!判斷式:
最終判斷結果之成立與否,乃是判斷式之成立與否的相反。
變數的設定(完全相同於在bash命令列中直接設定的方法,在此重複說明):
變數名稱有區分大小寫、不能以數字做名稱開頭。通常,大寫的變數名代表系統的內建變數或環境變數。
變數分為「一般變數」、「環境變數」、「系統變數」,以下先說明一般變數:
(1) 在宣告變數或為變數賦值的時候,語法為:變數名稱=值。
(2) 在呼叫變數的值時,變數名稱之前要加上一個$符號,如:$變數名稱。
$符號就是「取其值」的意思。也就是說,變數名稱是呼叫變數本身,$變數名稱是呼叫變數的值。
※(重要!) 此外,亦可以用 $(命令式) 來呼叫該命令式成功執行後顯示的資訊,範例如:
cmdtt1=$(date)
cmdtt2=date
echo $cmdtt1 #執行顯示:
正和在命令面板中輸入date是一樣的效果,顯示了當時的時間。
echo $cmdtt2 #執行顯示:#只顯示一般字串而已。
※ 要解除變數的宣告,需用:unset 變數名稱。
(3) 變數的種類:
(3-1) 字串:有三種宣告方法:
(3-1-1) 裸字串:即字串兩旁並不用任何符號框住。宣告方式為:變數名稱=字串。如:kk=dd,或 kk=1。這種裸字串的宣告方法有其規則:
※ 字串中不能包含錢號$,$會被當成呼叫變數用的符號。
※「連續或單一個空白字元」會被當成「單獨一個空白字元」。
※ 若要使字串中包含單引號 ' ,可用反斜線 \ 脫逸,如:
t2=gg\'\'
echo $t2
執行顯示:
※ 若要使字串中包含雙引號 " ,可用反斜線 \ 脫逸,如:
t2=gg\"\"
echo $t2
執行顯示:
(3-1-2) 單引號字串:即字串兩旁用單引號 ’ 框住。宣告方式為:變數名稱=’字串’ 。如:kk=’dd’,或 kk=’1’。在單引號字串中,
※ 錢號$被當成一個普通字元。
※ 雙引號 ” 被當成一個普通字元。如:
t1="200"
t2='gg$t1"f'
echo $t2
執行顯示:
(3-1-3) 雙引號字串:即字串兩旁用單引號 " 框住。宣告方式為:變數名稱=”字串” 。如:kk=”dd”,或 kk=”1”。在雙引號字串中,
※ 可以使用錢號$來呼叫變數之值。
※ 而單引號 ‘ 被當成一個普通字元。如:
t1="200"
t2="gg$t1'f"
echo $t2
執行顯示:
(3-1-4) 字串的運算:
要將一堆字串相加在一起,並不需特別的符號,只要將字串連著寫即可。如:
t1="kk"
t2="gg"
t3=$t1"123"$t2"456"
echo $t3
執行顯示:
(3-1-5) 取得子字串:
要取得子字串,可用:${字串名稱:N:L} 來取得字串中序數為N的字元算起的L個字元。其中,N從0開始,L個字元中包含序數為N的字元。如:
s="0123456789"
echo ${s:1:3}
執行顯示:
(3-1-6) 取得字串長度(也就是字元數):
使用:${#字串名稱} 可取得字串長度。
(3-1-7) 取代子字串:
※ 使用:${字串/子字串一/子字串二} 可將字串內第一個子字串一,用子字串二來取代,然後回傳其結果。
※ 使用:${字串//子字串一/子字串二} 可將字串內所有的子字串一,用子字串二來取代,然後回傳其結果。
(3-2) 整數:在Linux中並不支援浮點數,數字只能是整數類型。
(3-2-1) 整數的四則運算:
整數的四則運算和求餘數,並非直接輸入程式碼就好。如果是直接輸入程式碼,如:
t1=1
t2=10
echo $t1+$t2
執行後顯示:
顯示結果的型態是一個字串,並不是一個數字。
若要執行運算式,其語法應為:$((運算式)),如:
t1=1
t2=10
echo $((t1+$t2))
執行後顯示:
顯示結果的型態便是一個數字了。
※ 四則運算與求餘數的符號分別為 + 、 - 、 * 、 /、%。與一般程式語言無異。
(3-3) 布林值:
※ 宣告變數為真:變數名稱=true
※ 宣告變數為假:變數名稱=false
(3-4) 矩陣:
(3-4-1) 宣告矩陣變數,語法如:
變數名稱=(元素一 元素二 元素三 …)
其中,每個元素之間用空白字元相隔。範例如:
A=("kkk" "bbb" "123")
echo $A #顯示矩陣變數A的首元素。執行顯示:
echo ${A[1]} #顯示矩陣變數A中索引為1的元素(索引從0開始)。執行顯示:
(3-4-2) 相關用法:
※ 元素總數:${#矩陣變數名稱[@]} 會得出該矩陣的元素總數,其資料型態為整數,可直接拿來做數學運算。
* 朋友們若是覺得本教學對您有幫助,請按個讚~
一、前言:shell script的特色與用處:
(1) 可以把shell script當成一連串命令的集合(巨集)。一個shell script不用編譯就可執行。
(2) 可對主機(伺服器)執行自動化管理。
(3) 執行時會呼叫外部函式,執行速度較低於一般程式語言。
(4) 副檔名通常為 .sh。故一個shell script檔案也叫做「sh檔」。
(5) 以符號#作為註解符號,語法為:#註解內容
(6) 如何執行一個shell script程式檔?在命令列,利用指令:bash 程式檔名.副檔名 或是 sh 程式檔名.副檔名 即可。此外,還有一些方便的用法:
※ sh –n程式檔名.副檔名:不執行shell script程式檔,先為shell script程式檔除錯,若沒有錯誤則不顯示任何訊息。
※ sh –v程式檔名.副檔名:先顯示shell script程式檔內容,再執行shell script程式檔。
※ sh –x程式檔名.副檔名:逐行顯示shell script程式檔的執行過程。這是很實用的功能。
1. 基本輸入與輸出(與在bash中的基本輸入輸出完全一樣,在此重複說明):
(1) 基本輸入:
(1-1) 使用 read 變數名稱 來輸入,程式執行時會在命令列出現空行,供使用者輸入,輸入後的資料便存在該變數名稱中。
(1-2) 使用 read –p “提示”變數名稱 來輸入,程式執行時會在命令列出現提示字元以提示使用者要輸入的是什麼資料,同樣,輸入後的資料便存在該變數名稱中。
(1-3) 使用 read –t N 變數名稱 來輸入,系統會限制使用者必須在N秒內輸入,超過N秒,則輸入無效。
(2) 基本輸出:
使用 echo $變數名稱 來輸出。
範例如:
read -p "who are you?" who
echo "I'm " $who
執行後顯示:
輸入 kkk,如:
顯示: