什么是 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 release PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH echo -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.sh Hello 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.sh Please 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.sh Please input your first name: VBird Please input your last name: Tsai Your full name is: VBird Tsai [root@www scripts]# echo $firstname $lastname VBird 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