1、for/do/done
Shell指令碼的for迴圈結構和C語言很不一樣,它類似於某些程式設計語言的foreach迴圈。例如:
#! /bin/shfor FRUIT in apple banana pear; do echo "I like $FRUIT"done
FRUIT是一個迴圈變數,第一次迴圈$FRUIT的取值是apple,第二次取值是banana,第三次取值是pear。再比如,要將目前的目錄下的chap0、chap1、chap2等檔案名稱改為chap0~、chap1~、chap2~等(按慣例,末尾有~字元的檔案名稱表示臨時檔案),這個命令可以這樣寫:
$ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done
也可以這樣寫:
$ for FILENAME in `ls chap?`; do mv $FILENAME $FILENAME~; done
2、 while/do/done
while的用法和C語言類似。比如一個驗證密碼的指令碼:
#! /bin/shecho "Enter password:"read TRYwhile [ "$TRY" != "secret" ]; do echo "Sorry, try again" read TRYdone
下面的例子通過算術運算控制迴圈的次數:
#! /bin/shCOUNTER=1while [ "$COUNTER" -lt 10 ]; do echo "Here we go again" COUNTER=$(($COUNTER+1))done
Shell還有until迴圈,類似C語言的do...while迴圈。本章從略。
3、 位置參數和特殊變數
有很多特殊變數是被Shell自動賦值的,我們已經遇到了$?和$1,現在總結一下:
常用的位置參數和特殊變數
$0 |
相當於C語言main函數的argv[0] |
$1、$2... |
這些稱為位置參數(Positional Parameter),相當於C語言main函數的argv[1]、argv[2]... |
$# |
相當於C語言main函數的argc - 1,注意這裡的#後面不表示注釋 |
$@ |
表示參數列表"$1" "$2" ...,例如可以用在for迴圈中的in後面。 |
$? |
上一條命令的Exit Status |
$$ |
當前Shell的進程號 |
位置參數可以用shift命令左移。比如shift 3表示原來的$4現在變成$1,原來的$5現在變成$2等等,原來的$1、$2、$3丟棄,$0不移動。不帶參數的shift命令相當於shift 1。例如:
#! /bin/shecho "The program $0 is now running"echo "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@"shiftecho "The first parameter is $1"echo "The second parameter is $2"echo "The parameter list is $@"
4、函數
和C語言類似,Shell中也有函數的概念,但是函數定義中沒有傳回值也沒有參數列表。例如:
#! /bin/shfoo(){ echo "Function foo is called";}echo "-=start=-"fooecho "-=end=-"
注意函數體的左花括弧{和後面的命令之間必須有空格或換行,如果將最後一條命令和右花括弧}寫在同一行,命令末尾必須有;號。
在定義foo()函數時並不執行函數體中的命令,就像定義變數一樣,只是給foo這個名字一個定義,到後面調用foo函數的時候(注意Shell中的函數調用不寫括弧)才執行函數體中的命令。Shell指令碼中的函數必須先定義後調用,一般把函數定義都寫在指令碼的前面,把函數調用和其它命令寫在指令碼的最後(類似C語言中的main函數,這才是整個指令碼實際開始執行命令的地方)。
Shell函數沒有參數列表並不表示不能傳參數,事實上,函數就像是迷你指令碼,調用函數時可以傳任意個參數,在函數內同樣是用$0、$1、$2等變數來提取參數,函數中的位置參數相當於函數的局部變數,改變這些變數並不會影響函數外面的$0、$1、$2等變數。函數中可以用return命令返回,如果return後面跟一個數字則表示函數的Exit Status。
下面這個指令碼可以一次建立多個目錄,各目錄名通過命令列參數傳入,指令碼逐個測試各目錄是否存在,如果目錄不存在,首先列印資訊然後試著建立該目錄。
#! /bin/shis_directory(){ DIR_NAME=$1 if [ ! -d $DIR_NAME ]; then return 1 else return 0 fi}for DIR in "$@"; do if is_directory "$DIR" then : else echo "$DIR doesn't exist. Creating it now..." mkdir $DIR > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Cannot create directory $DIR" exit 1 fi fidone
注意is_directory()返回0表示真返回1表示假。