什麼是 Shell scripts
什麼是 shell script (程式化指令碼) 呢?就字面上的意義,我們將他分為兩部份。 在『 shell 』部分,我們在bash當中已經提過了,那是一個文字介面底下讓我們與系統溝通的一個工具介面。那麼『 script 』是啥? 字面上的意義, script 是『指令碼、劇本』的意思。整句話是說, shell script 是針對 shell 所寫的『劇本!』
什麼東西啊?其實, shell script 是利用 shell 的功能所寫的一個『程式 (program)』,這個程式是使用純文字檔,將一些 shell 的文法與命令(含外部命令)寫在裡面, 搭配正規標記法、管線命令與資料流重導向等功能,以達到我們所想要的處理目的。
shell script 更提供陣列、迴圈、條件與邏輯判斷等重要功能,讓使用者也可以直接以 shell 來撰寫程式,而不必使用類似 C 程式語言等傳統程式撰寫的文法呢!
撰寫第一支 script
在武俠世界中,不論是那個門派,要學武功要從掃地做起,那麼要學程式呢?呵呵,肯定是由『秀出 Hello World!』 這個字眼開始的!OK!那麼鳥哥就先寫一支 script 給大家瞧一瞧:
[root@www ~]# mkdir scripts; cd scripts[root@www scripts]# vi sh01.sh#!/bin/bash# Program:# This program shows "Hello World!" in your screen.# History:# 2005/08/23 VBird First releasePATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/binexport PATHecho -e "Hello World! \a \n"exit 0
在本章當中,請將所有撰寫的 script 放置到你家目錄的 ~/scripts 這個目錄內, 未來比較好管理啦!上面的寫法當中,鳥哥主要將整個程式的撰寫分成數段,大致是這樣:
- 第一行 #!/bin/bash 在宣告這個 script 使用的 shell 名稱:
因為我們使用的是 bash ,所以,必須要以『 #!/bin/bash 』來宣告這個檔案內的文法使用 bash 的文法!那麼當這個程式被運行時,他就能夠載入 bash 的相關環境配置檔 (一般來說就是 non-login shell 的 ~/.bashrc), 並且運行 bash 來使我們底下的命令能夠運行!這很重要的!(在很多狀況中,如果沒有配置好這一行, 那麼該程式很可能會無法運行,因為系統可能無法判斷該程式需要使用什麼 shell 來運行啊!)
- 程式內容的說明:
整個 script 當中,除了第一行的『 #! 』是用來宣告 shell 的之外,其他的 # 都是『註解』用途! 所以上面的程式當中,第二行以下就是用來說明整個程式的基本資料。一般來說, 建議你一定要養成說明該 script 的:1. 內容與功能; 2. 版本資訊; 3. 作者與聯絡方式; 4. 建檔日期;5. 曆史紀錄 等等。這將有助於未來程式的改寫與 debug 呢!
- 主要環境變數的宣告:
建議務必要將一些重要的環境變數配置好,鳥哥個人認為, PATH 與 LANG (如果有使用到輸出相關的資訊時) 是當中最重要的! 如此一來,則可讓我們這支程式在進行時,可以直接下達一些外部命令,而不必寫絕對路徑呢!比較好啦!
- 主要程式部分
就將主要的程式寫好即可!在這個例子當中,就是 echo 那一行啦!
- 運行成果告知 (定義回傳值)
是否記得我們討論一個命令的運行成功與否,可以使用 $? 這個變數來觀察~ 那麼我們也可以利用 exit 這個命令來讓程式中斷,並且回傳一個數值給系統。 在我們這個例子當中,鳥哥使用 exit 0 ,這代表離開 script 並且回傳一個 0 給系統, 所以我運行完這個 script 後,若接著下達 echo $? 則可得到 0 的值喔! 更聰明的讀者應該也知道了,呵呵!利用這個 exit n (n 是數字) 的功能,我們還可以自訂錯誤資訊, 讓這支程式變得更加的 smart 呢!
接下來透過剛剛上頭介紹的運行方法來運行看看結果吧!
[root@www scripts]# sh sh01.shHello World !
你會看到螢幕是這樣,而且應該還會聽到『咚』的一聲,為什麼呢?還記得前一章提到的 printf 吧?用 echo 接著那些特殊的按鍵也可以發生同樣的事情~ 不過, echo 必須要加上 -e 的選項才行!呵呵!在你寫完這個小 script 之後,你就可以大聲的說:『我也會寫程式了』!哈哈! 很簡單有趣吧~ ^_^
另外,你也可以利用:『chmod a+x sh01.sh; ./sh01.sh』來運行這個 script 的呢!
script 的運行方式差異 (source, sh script, ./script)
利用直接啟動並執行方式來運行 script
當使用前一小節提到的直接命令下達 (不論是絕對路徑/相對路徑還是 $PATH 內),或者是利用 bash (或 sh) 來下達指令碼時, 該 script 都會使用一個新的 bash 環境來運行指令碼內的命令!也就是說,使用者種運行方式時, 其實 script 是在子程式的 bash 內啟動並執行!父程式/子程式一些概念性的問題, 重點在於:『當子程式完成後,在子程式內的各項變數或動作將會結束而不會傳回到父程式中』! 這是什麼意思呢?
我們舉剛剛提到過的 sh02.sh 這個指令碼來說明好了,這個指令碼可以讓使用者自行配置兩個變數,分別是 firstname 與 lastname,想一想,如果你直接運行該命令時,該命令幫你配置的 firstname 會不會生效?看一下底下的運行結果:
[root@www scripts]# echo $firstname $lastname <==確認了,這兩個變數並不存在喔![root@www scripts]# sh sh02.shPlease input your first name: VBird <==這個名字是鳥哥自己輸入的Please input your last name: Tsai Your full name is: VBird Tsai <==看吧!在 script 運行中,這兩個變數有生效[root@www scripts]# echo $firstname $lastname <==事實上,這兩個變數在父程式的 bash 中還是不存在的!
上面的結果你應該會覺得很奇怪,怎麼我已經利用 sh02.sh 配置好的變數竟然在 bash 環境底下無效!怎麼回事呢? 如果將程式相關性繪製成圖的話,我們以來說明。當你使用直接啟動並執行方法來處理時,系統會給予一支新的 bash 讓我們來運行 sh02.sh 裡面的命令,因此你的 firstname, lastname 等變數其實是在中的子程式 bash 內啟動並執行。 當 sh02.sh 運行完畢後,子程式 bash 內的所有資料便被移除,因此上表的練習中,在父程式底下 echo $firstname 時, 就看不到任何東西了!這樣可以理解嗎?
利用 source 來運行指令碼:在父程式中運行
如果你使用 source 來運行命令那就不一樣了!同樣的指令碼我們來運行看看:
[root@www scripts]# source sh02.shPlease input your first name: VBirdPlease input your last name: TsaiYour full name is: VBird Tsai[root@www scripts]# echo $firstname $lastnameVBird Tsai <==嘿嘿!有資料產生喔!
竟然生效了!沒錯啊!因為 source 對 script 的運行方式可以使用底下的圖示來說明! sh02.sh 會在父程式中啟動並執行,因此各項動作都會在原本的 bash 內生效!這也是為啥你不登出系統而要讓某些寫入 ~/.bashrc 的配置生效時,需要使用『 source ~/.bashrc 』而不能使用『 bash ~/.bashrc 』是一樣的啊!
撰寫 shell script 的良好習慣建立
一個良好習慣的養成是很重要的~大家在剛開始撰寫程式的時候,最容易忽略這部分, 認為程式寫出來就好了,其他的不重要。其實,如果程式的說明能夠更清楚,那麼對你自己是有很大的協助的。
舉例來說,鳥哥自己為了自己的需求,曾經撰寫了不少的 script 來幫我進行主機 IP 的偵測啊、 登入檔分析與管理啊、自動上傳下載重要配置檔啊等等的,不過,早期就是因為太懶了, 管理的主機又太多了,常常同一個程式在不同的主機上面變更,到最後,到底哪一支才是最新的都記不起來, 而且,重點是,我到底是改了哪裡?為什麼做那樣的修改?都忘的一乾二淨~真要命~
所以,後來鳥哥在寫程式的時候,通常會比較仔細的將程式的設計過程給他記錄下來,而且還會記錄一些曆史紀錄, 如此一來,好多了~至少很容易知道我修改了哪些資料,以及程式修改的理念與邏輯概念等等, 在維護上面是輕鬆很多很多的喔!
另外,在一些環境的配置上面,畢竟每個人的環境都不相同,為了取得較佳的運行環境, 我都會自行先定義好一些一定會被用到的環境變數,例如 PATH 這個玩意兒! 這樣比較好啦~所以說,建議你一定要養成良好的 script 撰寫習慣,在每個 script 的檔頭處記錄好:
- script 的功能;
- script 的版本資訊;
- script 的作者與聯絡方式;
- script 的著作權宣告方式;
- script 的 History (曆史紀錄);
- script 內較特殊的命令,使用『絕對路徑』的方式來下達;
- script 運行時需要的環境變數預先宣告與配置。
除了記錄這些資訊之外,在較為特殊的程式碼部分,個人建議務必要加上註解說明,可以協助你非常非常多!
轉自 http://vbird.dic.ksu.edu.tw/linux_basic/0340bashshell-scripts_1.php