天天看點

Linux Shell程式設計入門

Linux的Shell種類衆多,常見的有:Bourne Shell(/usr/bin/sh或/bin/sh)、Bourne Again Shell(/bin/bash)、C Shell(/usr/bin/csh)、K Shell(/usr/bin/ksh)、Shell for Root(/sbin/sh),等等。不同的Shell語言的文法有所不同,是以不能交換使用。每種Shell都有其特色之處,基本上,掌握其中任何一種 就足夠了。在本文中,我們關注的重點是Bash,也就是Bourne Again Shell,由于易用和免費,Bash在日常工作中被廣泛使用;同時,Bash也是大多數Linux系統預設的Shell。在一般情況下,人們并不區分Bourne Shell和Bourne Again Shell,是以,在下面的文字中,我們可以看到#!/bin/sh,它同樣也可以改為#!/bin/bash。

利用vi等文本編輯器編寫Shell腳本的格式是固定的,如下:

#!/bin/sh

#comments

Your commands go here

首行中的符号#!告訴系統其後路徑所指定的程式即是解釋此腳本檔案的Shell程 序。如果首行沒有這句話,在執行腳本檔案的時候,将會出現錯誤。後續的部分就是主程式,Shell腳本像進階語言一樣,也有變量指派,也有控制語句。除第 一行外,以#開頭的行就是注釋行,直到此行的結束。如果一行未完成,可以在行尾加上",這個符号表明下一行與此行會合并為同一行。

編輯完畢,将腳本存盤為filename.sh,檔案名字尾sh表明這是一個Bash腳本檔案。執行腳本的時候,要先将腳本檔案的屬性改為可執行的:

chmod +x filename.sh

執行腳本的方法是:

./filename.sh

下面我們從經典的“hello world”入手,看一看最簡單的Shell腳本的模樣。

#print hello world in the console window

a = "hello world"

echo $a

Shell Script是一種弱類型語言,使用變量的時候無需首先聲明其類型。新的變量會在本地資料區配置設定記憶體進行存儲,這個變量歸目前的Shell所有,任何子進 程都不能通路本地變量。這些變量與環境變量不同,環境變量被存儲在另一記憶體區,叫做使用者環境區,這塊記憶體中的變量可以被子程序通路。變量指派的方式是:

variable_name = variable_value

如果對一個已經有值的變量指派,新值将取代舊值。取值的時候要在變量名前加$,$variable_name可以在引号中使用,這一點和其他進階語言是明顯不同的。如果出現混淆的情況,可以使用花括号來區分,例如:

echo "Hi, $as"

就不會輸出“Hi, hello worlds”,而是輸出“Hi,”。這是因為Shell把$as當成一個變量,而$as未被指派,其值為空。正确的方法是:

echo "Hi, ${a}s"

單引号中的變量不會進行變量替換操作。 

關于變量,還需要知道幾個與其相關的Linux指令。

env用于顯示使用者環境區中的變量及其取值;set用于顯示本地資料區和使用者環境區中的變量及其取值;unset用于删除指定變量目前的取值,該值将被指定為NULL;export指令用于将本地資料區中的變量轉移到使用者環境區。

下面我們來看一個更複雜的例子,結合這個例子,我們來講述Shell Script的文法。 

包含for循環及sed的用法

1 #!/bin/bash

2 # we have less than 3 arguments. Print the help text:

3 if [ $# -lt 3 ]; then

4 cat<<HELP

5      ren -- renames a number of files using sed regular expressions

7      USAGE: ren 'regexp' 'replacement' files

Linux Shell程式設計入門

8      EXAMPLE: rename all *.HTM files in *.html:

9      ren 'HTM$' 'html' *.HTM

10 

11 HELP

12      exit 0

13 fi

14 OLD="$1"

15 NEW="$2"

16 # The shift command removes one argument from the list of

17 # command line arguments.

18 shift

19 shift

20 # $* contains now all the files:

21 for file in $*; do

22 if [ -f "$file" ]; then

23     newfile=`echo "$file" | sed  "s/${OLD}/${NEW}/g"`

24         if [ -f "$newfile" ]; then

25             echo "ERROR: $newfile exists already"

26         else

27             echo "renaming $file to $newfile 

Linux Shell程式設計入門

"

28             mv "$file" "$newfile"

29         fi

30 fi

31 done

我們從頭來看,前面兩行上一個例子中已經解釋過了,從第三行開始,有新的内容。if語句和其他程式設計語言相似,都是流程控制語句。它的文法是:

if …; then

elif …; then

else

fi

與其他語言不同,Shell Script中if語句的條件部分要以分号來分隔。第三行中的[]表示條件測試,常用的條件測試有下面幾種:

[ -f "$file" ] 判斷$file是否是一個檔案

[ $a -lt 3 ] 判斷$a的值是否小于3,同樣-gt和-le分别表示大于或小于等于

[ -x "$file" ] 判斷$file是否存在且有可執行權限,同樣-r測試檔案可讀性

[ -n "$a" ] 判斷變量$a是否有值,測試空串用-z

[ "$a" = "$b" ] 判斷$a和$b的取值是否相等

[ cond1 -a cond2 ] 判斷cond1和cond2是否同時成立,-o表示cond1和cond2有一成立

要注意條件測試部分中的空格。在方括号的兩側都有空格,在-f、-lt、=等符号兩側同樣也有空格。如果沒有這些空格,Shell解釋腳本的時候就會出錯。

$#表示包括$0在内的指令行參數的個數。在Shell中,腳本名稱本身是$0,剩下的依次是$0、$1、$2…、${10}、${11},等等。$*表示整個參數清單,不包括$0,也就是說不包括檔案名的參數清單。

現在我們明白第三行的含義是如果腳本檔案的參數少于三個,則執行if和fi語句之間 的内容。然後,從第四行到第十一行之間的内容在Shell Script程式設計中被稱為Here文檔,Here文檔用于将多行文本傳遞給某一指令。Here文檔的格式是以<<開始,後跟一個字元串,在Here文檔結束的時候,這個字元串同樣也要出現,表示文檔結束。在本例中,Here文檔被輸出給cat指令,也即将文檔内容列印在螢幕上,起到顯示幫助 資訊的作用。

第十二行的exit是Linux的指令,表示退出目前程序。在Shell腳本中可以使用所有的Linux指令,利用上面的cat和exit,從一方面來說,熟練使用Linux指令也可以大大減少Shell腳本的長度。

十四、十五兩句是指派語句,分别将第一和第二參數指派給變量OLD和NEW。緊接下來的兩句是注釋,注釋下面的兩條shift的作用是将參數清單中的第一個和第二個參數删除,後面的參數依次變為新的第一和第二參數,注意參數清單原本也不包括$0。

然後,自二十一行到三十一行是一個循環語句。Shell Script中的循環有下面幾種格式:

while [ cond1 ] && { || } [ cond2 ] …; do

done

for var in …; do

for (( cond1; cond2; cond3 )) do

until [ cond1 ] && { || } [ cond2 ] …; do

在上面這些循環中,也可以使用類似C語言中的break和continue語句中斷 目前的循環操作。第二十一行的循環是将參數清單中的參數一個一個地放入變量file中。然後進入循環,判斷file是否為一個檔案,如果是檔案的話,則用sed指令搜尋和生成新的檔案名。sed基本上可以看成一個查找替換程式,從标準輸入,例如管道讀入文本,并将結果輸出到标準輸出,sed使用正規表達式 進行搜尋。在第二十三行中,backtick(`)的作用是取出兩個backtick之間的指令輸出結果,在這裡,也就是将結果取出賦給變量newfile。此後,判斷newfile是否已經存在,否則就把file改成newfile。這樣我們就明白這個腳本的作用了,Shell Script編寫的其他腳本與此相似,隻不過是文法和用法稍有不同而已。

通過這個例子我們明白了Shell Script的編寫規則,但還有幾件事情需要講述一下。

第一個,除了if語句之外,Shell Script中也有類似C語言中多分支結構的case語句,它的文法是:

case var in

pattern 1 )

… ;;

pattern 2 )

*)

esac

我們再就下面一個例子,看看case語句的用法。

while getopts vc: OPTION

do

case $OPTION in

c) COPIES=$OPTARG

ehco "$COPIES";;

v) echo "suyang";;

\?) exit 1;;

上面的getopts類似于C語言提供的函數getopts,在Shell Script中,getopts經常和while語句聯合起來使用。getopts的文法如下:

getopts option_string variable

option_string中包含一串單字元選項,若getopts在指令行參數中 發現了連字元,那麼它會将連字元之後的字元與option_string進行比較,若比對成功,則把變量variable的值設為該選項,若無比對,則把 變量的值設為?。有時候,選項還會帶一個值,例如-c5等,這時要在option_string中該選項字母後面加上一個冒号,getopts發現冒号 後,會讀取該值,然後将該值放入特殊變量OPTARG中。這個指令比較複雜,如有需要,讀者可以詳細參閱Shell編寫的相關資料。

上面這個循環的作用就是依次取出腳本名稱後面的選項,進行處理,如果輸入了非法選項,則進入"?指定的部分,退出腳本程式。

第二個,Bash提供了一種用于互動式應用的擴充select,使用者可以從一組不同的值中進行選擇。其文法如下:

select var in …; do

break;

例如,下面這段程式的輸出是:

#!/bin/bash

echo "Your choice?"

select var in "a" "b" "c"; do

break

echo $var

----------------------------

Your choice?

1) a

2) b

3) c

第三,Shell Script中也可以使用自定義的函數,其文法形式如下:

functionname()

{

}

例如我們可以把上面第二個例子中第四到第十二行放入一個名為help函數體内,以後每次調用的時候直接寫help即可。函數中處理函數調用參數的方法是,直接用上面講過的$1、$2來分别表示第一、第二個參數,用$*表示參數清單。

第四,我們也可以在Shell下調試Shell Script腳本,當然最簡單的方法就是用echo輸出檢視變量取值了。Bash也提供了真正的調試方法,就是執行腳本的時候用-x參數。

sh ?x filename.sh

這會執行腳本并顯示腳本中所有變量的取值,也可以使用參數-n,它并不執行腳本,隻是傳回所有的文法錯誤。

======================================================================

其它參考

        二、Shell簡易教程

        三、Vi的指令

<a href="http://down.51cto.com/data/2365738" target="_blank">附件:http://down.51cto.com/data/2365738</a>

本文轉自追光的貓部落格51CTO部落格,原文連結http://blog.51cto.com/ql0722/1655950如需轉載請自行聯系原作者

00_yatou