1. 程式人生 > >shell 結構化命令之跳轉

shell 結構化命令之跳轉

說到shell指令碼的結構化命令,我們不得不首先了解一下退出狀態碼的概念。shell中執行的每個命令都使用退出狀態碼(exit status)告訴shell它已經執行完畢。退出狀態碼是一個0-255的整數值,在命令結束執行時由命令傳給shell。我們可以獲取這個值並在指令碼中使用。

Linux中專門提供了變數$?來儲存上個已執行的命令的退出碼,它的值是shell所執行的最後一條命令的退出狀態碼。我們可以嘗試一下使用不同命令其退出狀態碼是什麼。

退出狀態碼

命令成功結束時,其退出狀態碼為0;如果有錯誤,退出碼就是一個正整數值,如126表示命令不可執行、127表示沒找到命令、128表示無效的引數等等。

exit命令:
預設情況下,shell指令碼會以指令碼中的最後一個命令的退出狀態碼退出,我們可以用exit n來自定義狀態碼,注意n要在0-255之間。

一、if-then語句

if-then語句格式如下:

if command
then    
    commands
fi

在bash shell中if後面的是一個命令,如果該命令的退出狀態碼是0(說明該命令執行成功),那麼位於then後面的命令才會被執行。注意,這和其他程式語言的if語句返回true或false不一樣。只要關注了這個,這個語句使用起來很容易:

if-then

二、if-then-else語句

在if-then語句中不管命令是否執行成功,你都只有一種選擇:成功則執行then中的命令;命令失敗則繼續往下執行。有的情況下,我們需要使用if-then-else語句:

if command
then 
    commands
else
    commands
fi

這個語句的使用也很直觀,請看以下示例:

if-else-then

三、巢狀if

如果使用上面的語句仍然不能很多好的滿足要求,那我們可以使用巢狀if來工作:

if command1
then 
    commands
elif command2
then
    commands2
fi

其實這裡只是將else裡面又嵌入了一個if-then語句,只是將else-if連起來寫成了elif;我們可以隨意組合巢狀,完成更復雜的邏輯。這裡就不做示例了,很簡單,並且後面經常會用到。

四、test命令

到目前為止,在if中用到的命令都是普通的shell命令,那麼if後面是否可以測試出退出狀態碼以外的條件呢? 是不能的,但是我們可以用test命令來測試其他條件,只要test命令中列出的條件成立,test命令就會退出並返回退出狀態碼0,這樣就可以完成類似於其他語言中那樣的if-then語句了。
test命令的格式非常簡單:test condition,condition是命令要測試的一系列引數和值相當於我們用test命令代替了之前的command命令。

test condition

如上圖所示,我們在test命令裡面測試一個存在的變數,會返回0,使得then中的語句會執行;相反則返回的退出狀態碼不為0。

test命令還有另一種常用的簡便寫法:單方括號 [ condition ],注意方括號距字串必須加上一個空格。test命令可以用來判斷三類條件:

  1. 數值比較
  2. 字串比較
  3. 檔案比較

下面我們來學習這幾種條件測試的使用方法,後面也會經常用到這些。

1、數值比較:
數值比較功能如下表,可以用在數字和變數上。

比較 描述
n1 -eq n2 檢查n1與n2是否相等(equal)
n1 -ge n2 檢查n1是否大於或等於n2(greater、equal)
n1 -gt n2 檢查n1是否大於n2(greater than)
n1 -le n2 檢查n1是否小於或等於n2(less、equal)
n1 -lt n2 檢查n1小於n2(less than)
n1 -ne n2 檢查n1與n2是否不相等(not equal)

~
需要記住,bash shell只能處理整數

2、字串比較:

比較 描述
str1 = str2 檢查str1和str2是否相同
str1 != str2 檢查str1和str2是不同
str1 < str2 檢查str1是否小於str2
str1 > str2 檢查str1是否大於str2
-n str 檢查str的長度是否非0
-z str 檢查str長度是否為0

~
這裡需要注意兩個問題:

  1. 大於號和小於號必須轉移,否則shell會把它們當做重定向符號,把字串當做檔名
  2. 大於小於的排序是按照ASCII碼的順序(即由小到大為0~9,A~Z,a~z)

我們編輯如下的指令碼,用來檢測變數是否長度為0。

#!/bin/bash

value1=testing
value2=""

if  [ -n $value1 ]
then
    echo "Then string $value1 not empty"
else
   echo "The string $value1 is empty"
fi

if [ -z $value2 ]
then 
    echo "The string $value2 is empty"
else
   echo "The string $value2 is not empty"
fi

if [ -z $value3 ] 
then 
    echo "The string $value3 is empty"
else
   echo "The string $value3 is not empty"
fi

執行輸出後,我們發現:定義了數值的變數長度不為0;而定義為空和未定義的變數其長度均為0。

Then string testing not empty
The string  is empty
The string  is empty

空的和為初始化的變數會對我們的指令碼造成很大的影響。如果不確定其值的內容,在使用之前,最好可以用-n或-z測試一下是否含有值。

3、檔案比較:
檔案比較是shell程式設計中很強大也最常用的比較形式,它允許你測試Linux檔案系統上的檔案和目錄的狀態。比較形式如下表:

比較 描述
-d file file是否存在並是一個目錄
-f file file是否存在並是一個檔案
-e file file是否存在
-r file file是否存在並且可讀
-w file file是否存在並且可寫
-s file file是否存在並且非空
-x file file是否存在並且可執行
-O file file是否存在並且屬當前使用者所有
-G file file是否存在並且預設組和當前使用者相同
file1 -nt file2 file1是否比file2新(new than)
file1 -ot file2 file1是否比file2舊(old than)

~
這些條件使用起來也是比較簡單的,我們應當先搞清楚邏輯再去做一系列的測試。

test file

如上所示,這裡我們直接比較了兩個檔案的新舊,然而我們並沒有確認這連個檔案是否存在,如果沒有存在的話,就可能得到一個錯誤的結果。我們可以使用布林運算子來組合測試:

#複合條件測試
[ condition1 ] && [ condition2 ] 
[ condition1 ] || [ condition2 ]

test -nt

五、使用雙小括號和雙方括號

雙小括號:
使用雙小括號來使用高階數學表示式,提供了很多其他程式語言類似的運算子。格式如下:

(( expression ))

能夠用在這裡的表示式很多,比如:i++、i–、++i、–i之類的;邏輯求反!;一些布林運算和位運算等等。在其他程式語言中可以用於的數學賦值或比較表示式等都可以用。

雙方括號:
雙方括號命令提供了針對字串比較的高階特性。雙方括號裡面的表示式使用了test命令中採用的標準字串比較。並且提供了模式匹配這個強大的特性。格式如下:

[[ expression ]]

雙方括號

我們再來總結一下幾種括號的使用:

方括號[ ]:類似於test命令,用判斷三類條件:數值、字串、檔案
雙小括號(( )):在比較中使用高階數學表示式
雙方括號[[ ]]:字串比較的升級-模式匹配(並不是所有shell都支援?)

六、case命令-簡化if-then-else

當我們嘗試在一組可能的值中尋找特定值,再來進行其他操作時。可能需要寫下很長的if-then-else語句,這時可以使用case語句來簡化指令碼,case命令的格式如下:

#可以通過或操作符|在一行中使用多個pattern
case variable in
pattern1) command1;;
pattern2) command2;;
*) default commands;;
esac

case

上面這個簡單的示例演示了獲取當前目錄並使用case來判斷在哪個目錄裡面。不難發現使用case的場景還是比較多的。

通過這一篇大致的熟悉了結構化命令中的跳轉語句,還有迴圈語句等者我們去學習呢。下篇預告:for/while/until等迴圈語句的使用。 :)