BASH SHELL 程式設計簡介:1.2版
如同在 Linux 中其他的 shell,Bourne Again SHell 不只是一個優秀的指令行 式的 shell,同時也提供 scripting 語言。Shell scripting 允許你完全利用 shell 的功能,將需要許多指令執行 的多項工作自動化。在你的 Linux 機器上有許多程式是 shell 程式。如果你對學習他們如何運作,或修改他們感興 趣,基本要素是你必須了解 bash 的語法和語意。除此之外,了解 bash 語言,你能夠 撰寫你個人專屬的程式,來完成你要做的事情。

PROGRAMMING OR SCRIPTING?
對於剛開始接觸程式設計的新手,常會對於 programming 和 scripting 語言間的差異感到困惑。Programming 語言 通常比 Scripting 語言功能更強大,也更快速。例如:C, C++, 和 Java 都是 Programming 語言。Programming 語 言通常是從原始碼 (一個包含最終程式如何執行的指令集合文字檔) 開始,經過編譯 (建立) 成為一個可執行檔。這 個可執行檔不容易移植到不同的作業系統中。舉例來說,如果你曾在 Linux 上寫過 C 的程式,你將不能夠在視窗 98 系統上執行這個 C 的程式。要這樣做,你必須在視窗 98 系統之下,重新編譯原始的程式碼。Scripting 語言也 是從原始碼開始,但不需編譯成可執行檔。而是由一個直譯器讀入原始碼檔案裡的那些指令,再執行每個指令。不幸 地,直譯的程式通常比編譯的程式慢,因為直譯器必須讀入每個指令。主要的優點是,你能輕鬆地轉換原始碼檔案到 任何的作業系統,並且立刻以直譯的方式執行。bash 是一種 scripting 語言。它對撰寫小程式而言 是不錯的,但如果你打算開發大型的應用程式,programming 語言可能對你比較有益。其他的 scripting 語言有 Perl, Lisp 和 Tcl 等等。

WHAT DO YOU NEED TO KNOW? / 那些是你需要知道的?
撰寫你自己的 shell 程式,需要知道最基本的 Linux 指令。舉例來說,你應該知道要如何拷貝,移動,產 生新檔案等等。還有一件事你必須知道,該如何使用文書編輯程式。在 Linux 裡有三個主要的文字檔編輯程式 - vi, emacspico。如果對 viemacs 並不熟悉,可用 pico 或一些其他容易使用文字檔編輯程式。

WARNING!!! / 警告!!!
以 root 的身份來練習!任何情況都可能發生!若你在撰寫程式時發生意外的錯誤,導致系統當掉,我並 不負責。你已被警告過了!一定要使用沒有 root 權限的一般使用者帳戶。你甚至可以產生一個新的使用者,專門來 練習 shell 程式設計。這樣,最糟的情況只是這個使用者的目錄不見了。

YOUR FIRST BASH PROGRAM / 第一個 BASH 程式
我們的第一個程式會是典型的 "Hello World" 程式。不要懷疑,若你已有程式設計的經驗,你現在又必須頭疼了。 然而,這是傳統,我何德何能改變傳統呢?"Hello World" 程式只是將 "Hello World" 這字眼列印到螢幕上。所以 趕快打開你的文字檔編輯程式,鍵入下列的內容:

#!/bin/bash
echo "Hello World"

第一行是告訴 Linux 用 bash 直譯器來執行這個程式。 在這個範例,bash 是位在 /bin 目錄下。如果在你的系統上,bash 是 在不同的目錄,請對這行做適當的更改。另外,要特別說明的是,這個直譯器是非常重要,所以請確定目錄正確否, 它告訴 Linux 哪一個直譯器用來執行程式中的那些指令。下一步是把將程式存檔。稱它做 hello.sh 好了。完成後,你需要讓此程式可以執行:

xconsole$ chmod 700 ./hello.sh

如果你不知道該如何更改檔案的權限,就參考 chmod 的手 冊(manual page)。一旦更改完成後,你僅需輸入程式的名字,就能執行了:

xconsole$ ./hello.sh
Hello World

就是這個光!就是這個光!你的第一個程式完成 了!真的就是這樣無聊,沒用,然而每個人都是這樣開始的。只需記得這個程式。撰寫程式碼,存成檔案,再用 chmod 讓它可執行。

COMMANDS, COMMANDS, COMMANDS / 指令,指令,指令
你的第一個程式要做什麼呢?列印 "Hello World" 這兩個字到螢幕上。但要怎樣做呢?使用指令。在程式中寫的唯 一一行程式碼是 echo "Hello World"。好吧,那一個是指令? echoecho 程式帶有一個參數,並將此參數列印到螢幕。

所謂參數是指在你所鍵入的程式名稱之後的任何東西 。在這個案例中,"Hello World" 是參數,它傳進 echo 指令中。若你輸入這樣的指令 ls /home/root ,那麼對 ls 而言, /home/root 是參數。就竟這代表 什麼呢?代表如果你有一支程式,可將參數列印到螢幕上,你就不需使用 echo 程式。我們假定有支 稱為 foo 的程式,能傳入一個參數,一個字串,並且將其列印到螢幕上。我們能同樣地重寫我們的程 式:

#!/bin/bash
foo "Hello World"

把它 存檔及更改存取模式(chmod),然後執行:

xconsole$ ./hello
Hello World

結果完全一樣。究竟有唯一的程式碼嗎?沒有。你真的能寫任 何程式?除非你是 echo 程式的作者。你所做的,是將 echo 程式放在你的 shell 程 式內,並給一個參數。在現實的世界中,例子中 echo 指令的另一選擇是 printf 指令 。printf 提供比較多的控制,如果你熟悉 C 語言的程式設計就會明瞭。事實上,要得到完全相同的 結果不必寫一個 shell 程式:

xconsole$ echo "Hello World"
Hello World

bash shell 程式設計提供了多樣的控制方式,而且容易學習。就如你 剛看到一樣,你用 Linux 指令來寫你的 shell 程式了。你的 shell 程式是將其他的程式聚集在一起,來執行特定 的任務。

A MORE USEFUL PROGRAM / 更有用的程式
我們將撰寫一個程式,功能是移動所有的檔案到一個目錄內,然後刪除此目錄及其內容,然後再產生此目錄。這可由 下列的指令來完成:

xconsole$ mkdir trash
xconsole$ mv * trash
xconsole$ rm -rf trash
xconsole$ mkdir trash

不需在交談式的 shell 上 敲進所有指令,改用撰寫個 shell 程式:

#!/bin/bash
mkdir trash
mv * trash
rm -rf trash
mkdir trash
echo "Deleted all files!"

把它 以 clean.sh 存檔,現在你所要做的是執行 clean.sh,它會移動所有的檔案到一個目 錄,刪除他們,再產生目錄,而且列印一個訊息告訴你,它已成功地刪除所有的檔案。所以記得,如果你發現要做的 某些事,要一而再,再而做三地做下去,考慮用個 shell 程式來自動執行。

COMMENTS / 註解
註解可讓你的程式更容易明瞭,這樣並不影響程式的輸出結果。目的就是來特別幫你明瞭程式。所有在 bash 裡的註解,第一個字元都是用井字符號(hash symbol):"#",除了第一個行 ( #!/bin/bash) 外。 第一行並不是註解。在第一行之後,其餘以 "#" 開始的任何一行都是註 解。看下列的程式片段:

#!/bin/bash
# 這個程式從 1 記錄到 10:
for i in 1 2 3 4 5 6 7 8 9 10; do
echo $i
done


即使你不知道 bash 的程式設計,因為註解的關係,也能立刻知道上述的程式在做什麼事。使用註解是很好的習慣。 你將發現若未來需要維護你的程式,有註解會比較容易。

VARIABLES / 變數
變數基本上是儲存數值的 "箱子(boxes)" 。有許多理由需要產生變數。做為儲存使用者輸入,參數或數字的數值。 舉下列的程式碼來說:

#!/bin/bash
x=12
echo "The value of variable x is $x"


剛才所做的,是給 x 變數一個數值 12 ,而 echo "The value of variable x is $x" 這行則是列印出目前變數 x 的 值。當你定義一個變數時,不能有任何的空白在設定運算元: "=" 之間。語法為:

variable_name=this_value

存取變數的數值藉由變數名稱前加一個錢字符號: "$" 進 行。如同上面的例子,我們用 echo $x 來存取變數 x 的數值。

變數有二種 類型。區域變數,和環境變數。環境變數是由系統設定的,通常藉由使用 env 指令來運用。環境變 數保有特別的數值。舉例來說,如果你鍵入:

xconsole$ echo $SHELL
/bin/bash

你會取得到目前執行 shell 的名字。環境變數被定義在 /etc/profile~/.bash_profile 中。echo 指令適合用來檢查目前區域和 環境變數的數值。若你對為何需要使用變數仍有疑問,在這裡有個相當好的例子:

#!/bin/bash
echo "The value of x is 12."
echo "I have 12 pencils."
echo "He told me that the value of x is 12."
echo "I am 12 years old."
echo "How come the value of x is 12?"

好,現在假設你決定要將 x 的數值用 8 代替 12,你要怎麼 做?你必須改變所有的程式碼中有 x is 12 的那幾行。等等... 程式碼中也有其他行有數字 12。你 也應該改變嗎?不,因為他們與 x 無關。感到困惑了?現在,在這裡有相同的例子,但它使用變數:

#!/bin/bash
x=12     # 設定變數 x 的值為 12
echo "The value of x is $x."
echo "I have 12 pencils."
echo "He told me that the value of x is $x."
echo "I am 12 years old." echo "How come the value of x is $x?"


在這裡,我們看見 $x 會列印出變數 x 目前的數值 12。所以現在,如果你 要改變 x 的數值為 8,必須做的是將 x=12 這行改成 x=8,程式會自 動地將所有有 $x 那幾行顯示成 8,代替原本的 12。其他行並不受影響。變數也有其他重要的用途 ,稍後會看得到。

CONTROL STRUCTURES / 控制性結構
控制性結構讓你的程式可做判斷而且 使他們更緊湊。更重要的是,它讓我們可做錯誤的檢查。到目前為止,我們所寫的程式是從頭到尾執行,直到沒有 指令為止。舉例來說:

#!/bin/bash
cp /etc/foo .
echo "Done."

這個短短的 shell 程式,稱它 bar.sh 好了,拷貝一個名為 /etc/foo 的檔案到目前的目錄內,並列印 "Done" 到螢幕上。這個程式只在一個條件之下可運作,就是你 必須有個名為 /etc/foo 的檔案,否則會發生什麼:

xconsole$ ./bar.sh
cp: /etc/foo: No such file or directory
Done.

就像你看到的,有問題。並不是執行你的程式的每個人,他們的系統裡有 /etc/foo 這個檔。如果你 的程式能檢查是否有 /etc/foo 檔案存在,然後若真的存在,再著手進行拷貝,否則,就離開。這樣 或許會是比較好的。在虛擬的程式碼中,將會是像這樣:

if /etc/code exists, then
    copy /etc/code to the current directory
    print "Done." to the screen.
otherwise,
    print "This file does not exist." to the screen
    exit


能在 bash 中實作嗎?當然可以! bash 的控制性結構計有,if, while, until, forcase。每個結構都是成對的,意思是起始用個 "標籤",終止也用個 "標籤"。舉例來說,if 結構開始為 if,結束時為 fi。控制性結構並不是在你系統上的程式,他們是 在 bash 中的一項功能(feature)。這意謂著,你將可寫自己的程式碼,並不只是將其他程式包在 shell 程式中。

if ... else ... elif ... fi
最常用的結構之一就是 if 結構。它允 許你的程式下判斷,就像是 "如果這條件存在,執行它,其餘的,執行其他的東西"。要發揮 if 結構 的功效,我們就必須使用 test 指令。test 檢查條件的狀況,也就是說,存在的檔案, 權限,或類似和不同等狀況。以下為重寫過的 bar.sh

#!/bin/bash
if test -f /etc/foo
then
    # 檔案存在,則拷貝檔案然後列印出一個訊 息
    cp /etc/foo .
    echo "Done."
else
    # 檔案不 存在,則列印出一個訊息然後離開
    echo "This file does not exist."
    exit
fi

注意我們在 thenelse 之後的敘述用鋸齒狀排列 。鋸齒狀排列是選擇性的,但這樣感覺上容易明瞭,哪些敘述在哪一條件下被執行。現在執行這個程式。如果你有 /etc/foo 這個檔案,那麼它將會拷貝檔案,否則,它將會列印錯誤訊息。test 檢查 是否檔案 /etc/foo 存在。選項 -f 檢查參數是否是一般性的檔案。以下是 test 的選項:

-d 檢查此 file 是否是一個目錄
-e 檢查此 file 是否存在
-f 檢查此 file 是否為一般的檔案
-g 檢查此 file 是否有 SGID 權限
-r 檢查此 file 是否可以讀取
-s 檢查此 file 大小是否不為 0
-u 檢查此 file 是否有 SUID 權限
-w 檢查此 file 是否可以寫入
-x 檢查此 file 是否可以執行

else 是用在若第一個條件不匹配時,還要你 的程式做別的東西。另有個 elif,可用在 if 結構中還有另一個 if 的時候。基本上 elif 代表 "else if",當第一個條件不匹配,而你想要測試另外的條件時,可用它 。

http://linuxfab.cx/indexColumnData.php?CID=28&CPAGE=3