Linux 基礎學習篇 - Mandrake 9

第十二章、學習 shell scripts - for Mandrake 9

鳥哥的第一本書籍的主要內容,內容稍微與書籍不太一樣了!

最近更新時間: 2002/06/27

鳥哥的第一本書大約是在 2002 年的年底左右出版的,內容幾乎都是 Linux 基礎學習,一點也沒有談到伺服器的部份!這也是後來的雛型! 不過內容錯誤的地方很多,導致在 2003 年的年底推出了『基礎學習篇增訂版』的內容,大致上就是處理掉一些比較有嚴重錯誤的部份。 不過,因為 Linux 的版本變化非常快速,因此,寫完了這些文件之後,鳥哥還是持續在網站上更新文件內容,導致原本書籍內容的資料與網站資料差異太大! 這個問題直到鳥哥在 2008 年左右才發現!糟糕了!舊版的文件資料已經遺失~覺得相當扼腕~

因此,在底下的文件內容與當初的書籍內容雖然大同小異,不過章節的編排卻是有所不同!再花時間去一個一個處理,似乎也不太符合成本效益! 鳥哥僅是想要將自己以前的文件記錄下來而已,同時將過時的 big5 編碼改回 utf8 編碼,再加上可以支援 RWD 的樣式而已啦! 內容已經不多做編排~因此,如果內容文件你看不懂,那也是應該的! ^_^

建議您前往本站查詢最新版本的 Linux distribution 文章來閱讀,比較不會浪費時間。最新文章請前往鳥站首頁查閱囉!

幹嘛學習 Scripts

這個問題可有趣的很了,我為什麼要學習 scripts 呢?不要學可不可以呀!?呵呵!如果您只想要『會用』 Linux 就好的話,那麼這一個部分確實可以先跳過去不看也沒關係,不過,如果您想要更加的瞭解與控制 Linux ,使 Linux 運作更順暢之外,還可以高枕無憂的讓你的 Linux Server 在 Internet 上面提供相關服務的話,那麼 scripts 還是多少學一學吧!為什麼呢?因為 scripts 可以設計到『很聰明的知道什麼條件之下需要進行什麼動作!』不要小看這個功能呦!當您不在電腦前面的時候,突然之間,主機被一些不明封包試圖入侵了,這個時候如果你的 Linux 主機可以透過『當該封包嘗試幾次還是連線失敗之後,就予以抵擋住該 IP 』,如果可以設計到如此功能的話,呵呵!那麼可就不得了了!您的 Linux 主機就可以說是『好聰明呀! smart!』

除了針對主機之外,其實 scripts 還有相當多的運用功能呦!例如您想要在 Linux 上面作你的作業,而這個作業是一些數值方面的計算,這個時候 Scripts 也可以幫您計算呦!還不需要用到 fortran, c 這類高階的程式語言呢! scripts 本身就是一個可以用的 program 囉!相當的棒吧!其實, scripts 最開始被新手使用的功能就是『彙整一些在 command line 下達的連續指令,將他寫入 scripts 當中,而由直接執行 scripts 來啟動一連串的 command line 指令輸出入!』例如: 防火牆連續規則 ( iptables ),開機載入程序的項目 ( 就是在 /etc/rc.d/rc.local 裡頭的資料 ) ,等等都是相似的功能啦! 其實,說穿了,如果不考慮 program 的部分,那麼 scripts 也可以想成,僅是幫我們把一大串的指令彙整在一個檔案裡面,而直接執行該檔案就可以執行那一串又臭又長的指令段!就是這麼簡單啦!

另外的另外,在編寫 scripts 時,在 Linux 當中,最常使用的就是 vi 這一套文書編輯器了,所以囉,為了更簡易的控管我們的 Linux ,嗯!還是學習一下好了啦!好不好呀! ^_^

scripts 的執行與第一支 scripts

  • scripts 的執行:
嗯!在上一章 bash shell 當中說了一堆變數啦!管線指令啦!等等的,都是為了接著而來的 scripts 的咚咚啦!什麼是 script 啊?由字面上的意思來說, script 就是『腳本、劇本』的意思,那夠清楚了吧!就是將我們要執行的內容寫成一個『腳本』,讓系統依據這個『腳本』來執行我們想要的東西!好了!現在我們來討論一下怎麼寫 scripts 好了!基本上,一個 script 被執行的時候, bash 會據以判斷執行的步驟為:
  1. 如果讀取到一個 Enter 符號( CR ),就嘗試開始執行該行命令;
  2. 如同前面 bash command 提到的,指令間的多個空白會被忽略掉;
  3. 而空白行也將被忽略掉!,並且 tab 也是不會被理會的!
  4. 至於如果一行的內容太多,則可以使用 \ 來延伸至下一行;
  5. 此外,使用最多的 # 可做為註解!任何加在 # 後面的字,將全部被視為註解文字而被忽略!
然後,在撰寫一個 scripts 的時候,最好養成良好的習慣:
  1. 先宣告使用的 shell 為何?(特別留意這一點,在某些狀況中,例如 /etc/crontab 情況下,如果沒有宣告使用的 shell ,常常會出現錯誤訊息而導致 scripts 無法被執行呦!)
  2. 註明該 script 的內容功能、版本資訊、作者、建檔日期等等
  3. 每一個大步驟的主要功能(也順便提供自己未來修改之用!)
那麼 scripts 這個檔案要如何來執行呢?執行的方法有兩種:
  • 一個是將該檔案改成可以執行的屬性,如chmod 755 scripts.file ,然後執行該檔案;
  • 另一種則是直接以 sh 這個執行檔來執行 script 的內容,如 sh scripts.file
大致上就是這樣啦!OK!那麼還記得我們在前面一章已經說過了變數的設定方式了吧?好了,那麼我們就以第一支 scripts 來將我們設定的變數直接給他 show 出來!嗯!來設計一下這支 script 吧!
  • 建立你的第一支 script:
好了,我們來建立第一支簡單的 script 吧!最簡單的一個例子,就是在螢幕上列出『 Hello ! How are you ?』,可以這樣寫:(註:最常使用來作為 shell scripts 的寫作的軟體,就是 vi 啦!有空真的要多熟悉一下 vi 呦!)
 
[root @test /root]# mkdir test; cd test  <==建立一個新的目錄,所有的 scripts 都暫存在此!
[root @test test]# vi test01-hello.sh
#!/bin/bash                        <==在 # 之後加上 ! 與 shell 的名稱,用來宣告使用的 shell
# 這個腳本的用途在於列出 Hello ! How are you 在螢幕上
# 建檔日期: 2002/05/20
# Made by VBird
hello=Hello\ \!\ How\ are\ you\ \?      <==這就是變數啦!
echo $hello

[root @test test]# sh test01-hello.sh
Hello ! How are you ?                   <=輸出的結果顯示在螢幕上!

這裡給他注意一下:

  • 所有在 scripts 裡面的東西,基本規則 ( 如變數設定規則 ) 需要與 command line 時相同;
  • scripts 的附檔名最好為 .sh 提供他人的認識;
  • 並非加上 .sh 就可以是執行檔,還需要查看其屬性中是否有 x 這個屬性。
呵呵!很興奮吧!你已經會寫 scripts 了呦!已經具有初階的程式設計能力囉!嗯!是該覺得高興的!^_^...!好了,接著下來我們寫稍微複雜一點的,若一個 script 裡頭有兩個以上的變數要相互引用呢?呵呵!這個時候順便來比較一下 " 與 ' 的異同吧!
 
[root @test test]# vi test02-2var.sh
#!/bin/bash 
# 這個腳本用途在於引用兩個變數,順便比較一下 " 與 ' 的異同
# Date: 2002/06/27
# Made by VBird
name="V.Bird"
myname1="My name is $name"
myname2='My name is $name'
echo $name
echo $myname1
echo $myname2

[root @test test]# sh test02-2var.sh
V.Bird
My name is V.Bird
My name is $name

看到輸出的結果了吧!呵呵!沒錯!那個 " 與 ' 最大的不同就是在於能不能保有『變數內容』啦!再提醒一次,那個單引號『 ' 』裡頭的資料都將變成『單純的字元』而不是有特殊的字體呦!

標籤與運算符號: declare

    OK!瞭解了變數的 scripts 寫法之後,現在我們來進行一個有趣的實驗好了!就是說,當我們在進行『計算』的時候,到底 bash 能不能瞭解我們所給予的是『數字』還是單純的『字元』呢?這個很重要的,因為會造成系統的誤判呦!好了,我們來試試看!當我們需要輸出 3 * 5 的結果時,需要如何做呢?用單純的 command line 一行一行輸入的結果如下:
     
    [root @test test]# a=3
    [root @test test]# b=5
    [root @test test]# c=$a*$b
    [root @test test]# echo $c
    3*5  <==糟糕!怎麼變成了字串了?!

    發現了嗎?嘿嘿!上面輸出的是不是我們所希望的 3*5 = 15 的結果?嗯!這是因為我們沒有定義該變數,則該變數預設是呈現『字串』的型態!那麼自然 $c 就成為自串型態了!所以我們需要來宣告一下變數(嘿嘿!跟程式語言很相近吧!也是需要宣告變數的啦!),宣告變數使用的是 declare 這個指令,而變數名稱有底下這些囉!


  • declare

  • 宣告變數內容
    語法
    [test @test test]# declare [-afirx]
    參數說明:
    -a  :定義為陣列 array
    -f  :定義為函數 function 
    -i  :定義為整數 integer
    -r  :定義為『唯讀』
    -x  :定義為透過環境輸出變數
    範例:
    [test @test test]# declare -i a=3
    [test @test test]# declare -i b=5
    [test @test test]# declare -i c=$a*$b
    [test @test test]# echo $c
    15  <==變成數字囉! ^_^
初步瞭解了吧!?好了,現在我們來玩玩看,如果您的計算結果當中,需要輸入為 2*3+5*13-32+25 時,並且在最後輸出『 Your result is ==> 』該怎樣寫這一支簡單的 script 呢?可以這樣試試看:
 
[root @test test]# vi test03-declare.sh
#!/bin/bash
# This program is used to "declare" variables
# VBird 2002/06/27
number1=2*3+5*13-32+25
declare -i number2=2*3+5*13-32+25
echo "Your result is ==> $number1"
echo "Your result is ==> $number2"
[root @test test]# sh test03-declare.sh
Your result is ==> 2*3+5*13-32+25
Your result is ==> 64

怎樣?很有趣吧!更好玩的還在後頭呦!再往下看一下吧!

對談式 scripts :

什麼是對談式的 scripts 呢?很簡單啦!例如你在執行 Windows 的安裝程式時,系統不是常常會跳出一個視窗,問你『下一步』、『上一步』或『取消』嗎?那就是對談啦!程式會依據您輸入的資料來進行判斷,OK!那麼最簡單的對談式指令是什麼呢?呵呵!就是 read 這個指令啦! read 的功能就是『依據您在鍵盤輸入的結果 input 到變數內容中』,例如:
 
[root @test test]# read name
VBird <==這是鍵盤輸入的結果
[root @test test]# echo $name
VBird

好了!那麼我們來設定一下,當您的 script 在執行的時候,將您由鍵盤輸入的資料列出來!如何做呢?
 

[root @test test]# vi test04-read.sh
#!/bin/bash
# This program is used to "read" variables
# VBird 2002/06/27
echo "Please keyin your name, and press Enter to start."
read name
echo "This is your keyin data ==> $name"
[root @test test]# sh test04-read.sh
Please keyin your name, and press Enter to start.
VBird Tsai
This is your keyin data ==> VBird Tsai

就是這麼簡單,我們後面還會繼續的談到判別式,那個時候輸入的資料可就更重要了!

好了!下一步我們再來說一說怎樣定義一個 script 的參數的代號!?以底下我們的說明為例:
 
[root @test test]# myscript opt1 opt2 opt3 opt4
          $0    $1  $2  $3  $4

這是什麼意思呢?嘿嘿!就是說,在這個 script ( myscript )裡面,只要變數名稱為 $0 就表示為 myscript 這個咚咚,也就是說:

$0 : myscript 亦即是 script 的檔名
$1 : opt1 亦即是第一個附加的參數 (parameter)
$2 : opt2
$3 : opt3
這樣說或許不是很清楚,我們來玩一玩底下這個 script 看看就曉得他的意思啦!
 
[root @test test]# vi test05-0123
#!/bin/bash
# This program will define what is the parameters
# VBird 2002/06/27
echo "This script's name => $0"
echo "parameters $1 $2 $3"
[root @test test]# sh test05-0123 pa1 pa2 pa3
This script's name => test05-0123
parameters pa1 pa2 pa3

這個東西在運用上也是相當的重要的,例如當您要取得 script 的名稱時(因為有時候使用者會自行更改檔案名稱),則這個功能變數就相當的重要了!瞭解乎!?

scripts 邏輯判斷式與運算式:

再來的這個東西可就更重要了,尤其在 scripts 當中!那就如『如何判定某個檔案或目錄,或者是如何判定程式應該朝向那個方向行進』?這個東西需要有比較好一些的邏輯概念的說明才行!底下我們分別說明一下邏輯判斷式與運算式之後,再來設定幾個小 scripts 試試看不同的用法,以期得到大家的瞭解囉!
  • 邏輯判斷式:

  • 在 scripts 裡頭很重要的一項工作就是『判斷是否可行』的目標!舉個例子來說,當我們要建立一個目錄的時候,先偵測有沒有該目錄,如果有的話,那麼就不需要建立,如果沒有的話,那麼就建立該目錄!這個就需要 script 來主動的判斷了!那麼如何判斷呢?基本上由於是判斷式,那麼應該都會與『條件』有關的,所以底下的判斷式大多與『 if... then... fi 』這一種條件判斷式有關係!這部份後面再提,這裡先提一下邏輯判斷式的幾個重要的咚咚:
     
    邏輯標籤
    表示意思
    1. 關於檔案與目錄的偵測邏輯標籤!
    -f
    常用!偵測『檔案』是否存在
    -d
    常用!偵測『目錄』是否存在
    -b
    偵測是否為一個『 block 檔案
    -c
    偵測是否為一個『 character 檔案
    -S
    偵測是否為一個『 socket 標籤檔案
     -L
    偵測是否為一個『 symbolic link 的檔案
     -e
    偵測『某個東西』是否存在!
    2. 關於程序的邏輯標籤!
    -G
    偵測是否由 GID 所執行的程序所擁有
    -O
    偵測是否由 UID 所執行的程序所擁有
    -p
    偵測是否為程序間傳送資訊的 name pipe 或是 FIFO (老實說,這個不太懂!)
    3.  關於檔案的屬性偵測!
    -r
    偵測是否為可讀的屬性
    -w
    偵測是否為可以寫入的屬性
    -x
    偵測是否為可執行的屬性
    -s
    偵測是否為『非空白檔案
    -u
    偵測是否具有『 SUID 』的屬性
    -g
    偵測是否具有『 SGID 』的屬性
    -k
    偵測是否具有『 sticky bit 』的屬性
    4. 兩個檔案之間的判斷與比較 ;例如『 test file1 -nt file2
    -nt
    第一個檔案比第二個檔案新
    -ot
    第一個檔案比第二個檔案舊
    -ef
    第一個檔案與第二個檔案為同一個檔案( link 之類的檔案)
    5. 邏輯的『和(and)』『或(or)』
    &&
    邏輯的 AND 的意思
    ||
    邏輯的 OR 的意思

    比較有趣的應該算是 1, 3 這兩種種類的判斷,尤其是在建立一些 permission 相關的檔案時,這個就更重要了!然後那個『兩個檔案之間的判斷』也是挺有意思的!有空的話不妨去試一試去!還有,那個 &&|| 這兩個東西也是很重要的!接著下來,我們要來談一談運算符號囉!

  • 運算符號簡介:

  • 在 bash shell scripts 的運算符號的加減乘除是怎樣的一回事呀!?談一談吧!
     
    運算符號
    代表意義
    =
    等於
    !=
    不等於
    <
    小於
    >
    大於
    -eq
    等於
    -ne
    不等於
    -lt
    小於
    -gt
    大於
    -le
    小於或等於
    -ge
    大於或等於
    -a
    雙方都成立(and)
    -o
    單方成立(or)
    -z
    空字串
    -n
    非空字串

    邏輯判斷式與 if...then...fi 的關係是密不可分的,我們底下就先來談一談這一個判斷式當中最常使用的語法吧!

條件式判斷: if...then...fi, case.....esac

  • 條件判斷一:if then fi 的方式
OK!剛剛我們 建立了第一支 script ,在螢幕上面以 script 來輸出問候語!好了,現在我們如果要讓 scripts 加上『判斷』要如何來工作呢?這就是所謂的條件式判斷了!最常使用到的就是『 if ... then .... else if .... then ... end if 』的作法了!這個條件判斷的語法為:
 
if [ 條件判斷一 ] && (||) [ 條件判斷二 ]; then       <== if 是起始的意思,後面可以接若干個判斷式,使用 && 或 ||
    執行內容程式
elif [ 條件判斷三 ] && (||) [ 條件判斷四 ]; then     <==第二段的判斷,如果第一段沒有符合就來此搜尋條件
    執行第二段內容程式
else                                            <==當前兩段都不符合時,就以這段內容來執行!
    執行第三段內容程式
fi                                              <==結束 if then 的條件判斷!

上面的意思是這這樣的:在中刮號『[]』裡面的是條件式,如果是複合式的條件判斷(如若A及B則C之類的邏輯判斷),那麼就需要在兩個中刮號之間加上『 && (and)』或者是『 || (or)』這樣的邏輯運算式才行!如果是多重選擇的話,那麼就需要以 elif (optional, 選擇性的,若有需要才加上!)來新增另一個條件;如果所有的條件都不適用,則使用 else (optional)來進行最後的執行內容囉!

不過,這裡有幾個新手常犯的錯誤,我們需要來加強說明一下:
  1. 在 [ ] 當中,只能有一個判別式;
  2. 在 [ ] 與 [ ] 當中,可以使用 && 或 || 來組織判別式;
  3. 每一個獨立的元件之間『都需要有空白鍵來隔開』!
尤其是最後一點,最容易犯的錯啦!好了,我們來進行一個簡單的判別式好了!
 
[root @test test]# vi test06-ifthen.sh
#!/bin/bash
# This program is used to study if then
# VBird 2002/06/27
echo "Press y to continue"
read yn
if [ "$yn" = "y" ]; then
        echo "script is running..."
else
        echo "STOP!"
fi
[root @test test]# sh test06-ifthen.sh
Press y to continue
y
script is running...
[root @test test]$ sh test06-ifthen.sh
Press y to continue
n
STOP!

很簡單的一個例子吧!當輸入為 y 的時候,就給他進行,若非為 y 則不予以進行!但是這裡有個問題,就是如果我輸入為 Y 時,程式還是停止了!怎麼辦?!這個時候就需要使用到 || 這個東西啦!我們可以這樣做!
 

[root @test test]# cp test06-ifthen.sh test07-ifthen.sh
[root @test test]# vi test07-ifthen.sh
#!/bin/bash
# This program is used to study if then
# VBird 2002/06/27
echo "Press y to continue"
read yn
if [ "$yn" = "y" ] || [ "$yn" = "Y" ]; then
        echo "script is running..."
else
        echo "STOP!"
fi
[root @test test]# sh test07-ifthen.sh
Press y to continue
y
script is running...
[root @test test]$ sh test07-ifthen.sh
Press y to continue
Y
script is running...

好了!那麼如果再加上前面提過的: parameter 的選用呢?呵呵!這個也蠻有趣的,我們再來試試看:
 

[root @test test]# vi test08-ifthen.sh
#!/bin/bash
# set parameters in the if then
# 需要加上 hello 這個參數才會顯示正確的!
# VBird 2002/06/27
if [ "$1" = "hello" ]; then
        echo "Hello! How are you ?"
elif [ "$1" = "" ]; then
        echo "You MUST input parameters"
else
        echo "The only accept parameter is hello"
fi
[root @test test]# sh test08-ifthen.sh hello
Hello! How are you ?
[root @test test]$ sh test08-ifthen.sh
You MUST input parameters
[root @test test]$ sh test08-ifthen.sh djdkf
The only accept parameter is hello

呵呵!是不是不難呢?玩到這裡應該對於 scripts 的認識有一定程度的瞭解了吧!嗯!好了,底下我們來玩一個大的!假設您已經知道 netstat 與 grep 這兩個東西的用法,那麼如果要來偵測你的主機上面的 port 是否有開啟時,可以使用底下的範例來進行:
 

[test @test test]# vi port.sh                                  <==編輯一個檔案為 test1.sh 的 script
#!/bin/bash                                                     <==宣告使用的 shell 類型
# program: Using to study the [if ... then ... fi] program
# Made by:  VBird
# date:  2002/05/20
# content: I will using this program to show your services
# 1. print the program's work in your screen
  echo "Now, the services of your Linux system will be detect!"
  echo "The www, ftp, ssh, and sendmail + pop3 will be detect!"
  echo " "
# 2. www
  www=`netstat -an|grep LISTEN|grep :80`                    <==這個就是變數啦!並使用了管線命令!
  if [ "$www" != "" ]; then                                     <==開始條件的判斷囉!
      echo "WWW is running"                                <==若條件成立,那麼就列印這一行的內容!
  else
      echo "WWW is NOT running"
  fi
# 3. ftp
  ftp=`netstat -an|grep LISTEN|grep :21`
  if [ "$ftp" != "" ]; then
      echo "FTP is running"
  else
      echo "FTP is NOT running"
  fi
# 4. ssh
  ssh=`netstat -an|grep LISTEN|grep :22`
  if [ "$ssh" != "" ]; then
      echo "SSH is running"
  else
      echo "SSH is NOT running"
  fi
# 5. sendmail + pop3
  smtp=`netstat -an|grep LISTEN|grep :25`
  pop3=`netstat -an|grep LISTEN|grep :110`
  if [ "$smtp" != "" ]   && [ "$pop3" != "" ]; then           <==有兩個以上的條件式,就使用 && 或 || 來分隔!
      echo "sendmail is OK!"
  elif [ "$smtp" != "" ] && [ "$pop3"  = "" ]; then
      echo "sendmail have some problem of your pop3"
  elif [ "$smtp"  = "" ] && [ "$pop3" != "" ]; then
      echo "sendmail have some problem of your smtp"
  else
      echo "sendmail is NOT running"
  fi
[test @test test]# sh port.sh                                <==執行看看輸出的結果!
Now, the services of your Linux system will be detect!
The www, ftp, ssh, and sendmail + pop3 will be detect!

WWW is running
FTP is running
SSH is running
sendmail is OK!

很簡單吧!上面這樣就可以將你主機上面的資料進行解析囉!

  • 條件判斷二:使用 case ...esac 的方式
剛剛的『 if then fi 』的形式是以程式來自行判斷,那麼如果我已經規劃好幾個項目要來執行,只要選擇執行的『種類方式』就可以正確的執行的話,要怎麼做呢?最簡單的例子就是我們常常使用到的 /etc/rc.d/init.d/ 裡頭的 scripts 囉!例如:重新啟動 xinetd 是使用:
/etc/rc.d/init.d/xinetd restart
注意囉!那個是 restart 的項目,然後 script 就會自動的去搜尋 restart 項目裡面的情況去執行!那個就是 case ... esac 的使用模式囉!有沒有注意到,開始是『 case 』結束則是使用 case 的倒寫『 esac 』喝!很有趣吧!那麼這種格式是怎樣呢?
 
case 種類方式(string) in          <==開始階段,那個種類方式可分成兩種類型,通常使用 $1 這一種直接下達類型!
    種類方式一)
       程式執行段
       ;;                     <==種類方式一的結束符號!
    種類方式二)
       程式執行段
       ;;
    *)
       echo "Usage: {種類方式一|種類方式二}"     <==列出可以利用的參數值!
       exit 1
esac                         <==這個 case 的設定結束處!

在種類方式(string)的格式主要有兩種:

  1. 直接下達式:就是以『 執行檔案 + string 』的方式來執行的(/etc/rc.d/init.d 裡頭的基本設定方式),則 string 可以直接寫成『 $1 』(在執行檔案後面直接加入參數的第一個參數!)
  2. 互動式:就是由螢幕輸出可能的項目,然後讓使用者輸入,這個通常必須配合『 read variable 』然後 string 則寫成『 $variable 』的格式!
同樣的,我們建立一個名為 test2.sh 的檔案來試做看看。假如我們共可分三段格式來進行實作,分別為 one, two, three ,並假設使用直接下達式,則可以寫成:
 
[test @test test]# vi test09-case.sh
#!/bin/bash
# program:      Using case mode
# Made by:      VBird
# date:         2002/05/20
# content:      I will use this program to study the case mode!
# 1. print this program
  echo "This program will print your selection!"

case $1 in                                   <==使用直接下達指令型態!
  one)
        echo "your choice is one"
        ;;
  two)
        echo "your choice is two"
        ;;
  three)
        echo "your choice is three"
        ;;
  *)
        echo "Usage {one|two|three}"       <==列出可以使用的參數(如果使用者下達錯誤的參數時)
        exit 1
esac
[test @test test]# sh test09-case.sh       <==執行結果!顯示沒有相對的參數!所以列出可以參數!
This program will print your selection!
Usage {one|two|three}
[test @test test]# sh test09-case.sh three
This program will print your selection!
your choice is three

那麼對談式的 case 又如何呢?嗯!我們利用上面的方式來修改一下內容囉!
 

[root @test test]# vi test10-case.sh
#!/bin/bash
# program:      Using case mode
# Made by:      VBird
# date:         2002/06/27
# content:      I will use this program to study the case mode!
# 1. print this program
echo "Press your select one, two, three"
read number

case $number in
  one)
        echo "your choice is one"
        ;;
  two)
        echo "your choice is two"
        ;;
  three)
        echo "your choice is three"
        ;;
  *)
        echo "Usage {one|two|three}"
        exit 1
esac
[root @test test]# sh test10-case.sh
Press your select one, two, three
two   <=這一行是您輸入的呦!
your choice is two

如何!很簡單吧!以後對於 /etc/rc.d/init.d/ 裡頭的 script 就應該看的懂了吧!此外,由於還有所謂的『函數(function)』也就是『先將需要執行的程式段寫成一個小區塊,而這個小區塊則以一個名稱來取代之』,簡單的方式可以請您參考一下您系統中的 /etc/rc.d/init.d/sendmail !注意看一下 start() 底下的那些個咚咚!你就可以知道什麼意思了!由於我們這裡並不教你如何寫程式(基本上, scripts 就是小程式啦!還好! VBird 以前就有程式的底子!不然還真怕 script 呢!),所以就只好點到為止囉!

迴圈:for....do....done, while...do...done, until...do...done,

在程式段當中,最常使用到的就是迴圈了!迴圈是很重要的一項工具,尤其是具有判斷形式的迴圈,很常被使用來判斷一些事項的可行性與否!但是程式怎麼知道什麼時候應該要停止這個程式呢?呵呵!就需要加入判斷囉!好了,最簡單的判斷式可以是底下幾種:
  • for (( 條件一; 條件二; 條件三 ))
  • for variable in variable1 variable2 .....
  • while [ condition1 ] && { || } [ condition2 ] ...
  • until [ condition1 ] && { || } [ condition2 ] ...
for 是已經知道有多少個 run 了,即是已經知道要跑幾次了,至於 until 與 while 則分別是:
  • until:直到條件相同的時候才離開程式』;
  • while:當條件相同的時候,就繼續做!
這兩者不太相同的啦!
好了!我們先來談一下最簡單的迴圈,就是利用 for 這個東西來進行!好了,假設我們計算 1 + 2 + 3 .... + 100 ,以 script 要如何寫呢?有很多的方式,我們來談一談 do...done 好了!
 
[test @test test]# vi test11-loop.sh
#!/bin/bash
# Using for and loop
# VBird 2002/06/27
declare -i s  # <==變數宣告
for (( i=1; i<=100; i=i+1 ))
do
        s=s+i
done
echo "The count is ==> $s"

[test @test test]# sh test11-loop.sh
The count is ==> 5050

請注意! for (( 條件一; 條件二; 條件三)) 這是必須要的!

  • 條件一:這可以看成是『初始值』,如上面的例子中,初始值是 i=1 啦!
  • 條件二:這可以看成是『符合值』,如上面的例子中,當 i<=100 的時候都是符合條件的!
  • 條件三:這可以看成是『步階』!也就是說, i 每次都加一!
所以啦!上面的例子是說:由 i=1 開始到 i<= 100 ,每次 i 都加一來執行底下的程式段(就是 s=s+i ),當 i >100 (也就是 i=101 )就跳出這一段程式段!怎樣!不難吧!
好了!那麼使用 while 或者是 until 要怎樣執行呢?其實都是差不多的情況!我們使用底下的兩個 script 來進行 1 ~ 100 的累加動作!
 
1. 使用 while :
[test @test test]# vi test12-loop.sh
#!/bin/bash
# Using while and loop
# VBird 2002/06/27
declare -i i
declare -i s
while [ "$i" != "101" ]
do
        s=s+i
        i=i+1
done
echo "The count is ==> $s"

2. 使用 until :
[test @test test]# vi test13-loop.sh
#!/bin/bash
# Using until and loop
# VBird 2002/06/27
declare -i i
declare -i s
until [ "$i" = "101" ]
do
        s=s+i
        i=i+1
done
echo "The count is ==> $s"

[test @test test]# sh test12-loop.sh
The count is ==> 5050

嘻嘻嘻嘻!很簡單吧!

第二個例子來自於網友 jony 的提供!這是另外一種迴圈的方式,可以用來判斷非數字的類型呦!
 
[test @test test]# vi test14-for.sh
#!/bin/bash
# using for...do ....done
# VBird 2002/06/27

LIST="Tomy Jony Mary Geoge"

for i in $LIST
do
        echo $i
done

[test @test test]# sh test5.sh
Tomy
Jony
Mary
Geoge

這一種格式是以空白鍵當作 i 這個變數的選擇項目!也就是說,上面的 $LIST 這個變數當中,以空白鍵來分隔的時候,共可以分離出來四個!所以囉!當以 do ..... done ... 就可以分別寫出四個咚咚啦!好啦!那麼有沒有辦法利用這個東西來將你的 Linux 主機上的帳號 ( account ) 印出來呢?!很簡單呀!我們利用 cut 跟 sort 以及 /etc/passwd 這個檔案來完成這一支 script ,作法如下囉:
 

[test @test test]# vi test15-for.sh
#!/bin/bash
# Using for and loop to read the account of this linux server!
# VBird 2002/06/27
account=`cut -d ":" -f1 /etc/passwd|sort`
echo "The following is your linux server's account"

for i in $account
do
        echo $i
done

[test @test test]# sh test15-for.sh
The following is your linux server's account
adm
aerosol
alenchan
amanda
apache
....

OK!再來,我們來使用一下對談式的迴圈作用吧!嗯!當我們輸入 y 或 Y 時,程式就予以結束!該怎樣做?!
 

[test @test test]# vi test16-loop.sh
#!/bin/bash
# Using until
# VBird 2002/06/27

echo "Press Y/y to stop"
until [ "$yn" = "Y" ] || [ "$yn" = "y" ]
do
        read yn
done
echo "Stop here"

[test @test test]# sh test16-for.sh
Press Y/y to stop

GDSG
A
Y
Stop here

上面說的是,當輸入 Y 或者是 y 時才跳出 do...done 的迴圈之中!而去執行底下的東西!哈哈!很好玩吧!嗯!接著下來,我們來判斷一下目錄是否存在好了!這是常用的呦!

接下來我們判別一下所謂的『邏輯判斷式』的使用方式啦!剛剛我們不是已經知道了嗎,我們可以使用條件判斷來斷定到底有沒有檔案(用 -e )或者是該名稱是屬於目錄或者是檔案( -d -f ),接下來我們來判斷一個流程好了:
  1. 先查看一下 /root/test/logical 這個名稱是否存在;
  2. 若不存在,則建立一個檔案,使用 touch 來建立,建立完成後離開;
  3. 如果存在的話,判斷該名稱是否為檔案,若為檔案則將之刪除後建立一個檔案,檔名為 logical ,之後離開;
  4. 如果存在的話,而且該名稱為目錄,則移除此目錄!
看起來似乎很複雜,其實很簡單的啦!我們來試試看:
 
[test @test test]# vi test17-ifthen.sh
#!/bin/bash
# using if and then to select file or directory
# VBird 2002/06/27
if [ ! -e logical ]; then
        touch logical
        echo "Just make a file logical"
        exit 1
elif [ -e logical ] && [ -f logical ]; then
        rm logical
        mkdir logical
        echo "remove file ==> logical"
        echo "and make directory logical"
        exit 1
elif [ -e logical ] && [ -d logical ]; then
        rm -rf logical
        echo "remove directory ==> logical"
        exit 1
else
        echo "Does here have anything?"
fi

然後請你依序執行 sh test17-ifthen.sh ; ll 看看這個目錄底下 logical 那個檔案有什麼變化狀況!呵呵!瞭解了嗎?就是這麼簡單!這個動作可以讓我們很輕鬆的就判別到某個檔案的存在與否!嗯!不錯用!趕快來使用看看吧!

script 如何 debug

scripts 在執行之前,最怕的就是出現問題了!那麼我們如何 debug 呢?有沒有辦法不需要透過直接執行該 scripts 就可以來判斷是否有問題呢!?呵呵!當然是有的!我們就直接以 sh 來進行判斷吧!
 
[test @test test]# sh [-nvx] scripts
-n :不要執行 scripts ,查詢 scripts 內的語法,若有錯誤則予以列出!
-v :在執行 scripts 之前,先將 scripts 的內容顯示在螢幕上;
-x :將有使用到的 scripts 內容顯示在螢幕上,與 -v 稍微不同!
[test @test test]# sh -n test01-hello.sh
[test @test test]# sh -v test01-hello.sh
#!/bin/bash
# This program will print the "Hello! How are you" in your monitor
# Date: 2002/06/27
# User: VBird
hello="Hello! How are you"
echo $hello
Hello! How are you
[test @test test]# sh -x test01-hello.sh
+ hello=Hello! How are you
+ echo 'Hello!' How are you
Hello! How are you

熟悉 sh 的用法,將可以使您在管理 Linux 的過程中得心應手!
 
對於 Shell scripts 的學習方法上面,需要『多看、多模仿、並加以修改成自己的樣式!』是最快的學習手段了!網路上有相當多的朋友在開發一些相當有用的 scripts ,若是您可以將對方的 scripts 拿來,並且改成適合自己主機的樣子!那麼學習的效果會是最快的呢!

修改歷史:
  • 2002/06/27:第一次完成
  • 2003/02/10:重新編排與加入 FAQ
伺服器篇文件
各版本彙整說明
CentOS 6.x