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-else語句
在if-then語句中不管命令是否執行成功,你都只有一種選擇:成功則執行then中的命令;命令失敗則繼續往下執行。有的情況下,我們需要使用if-then-else語句:
if command
then
commands
else
commands
fi
這個語句的使用也很直觀,請看以下示例:
三、巢狀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命令裡面測試一個存在的變數,會返回0,使得then中的語句會執行;相反則返回的退出狀態碼不為0。
test命令還有另一種常用的簡便寫法:單方括號 [ condition ]
,注意方括號距字串必須加上一個空格。test命令可以用來判斷三類條件:
- 數值比較
- 字串比較
- 檔案比較
下面我們來學習這幾種條件測試的使用方法,後面也會經常用到這些。
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 |
~
這裡需要注意兩個問題:
- 大於號和小於號必須轉移,否則shell會把它們當做重定向符號,把字串當做檔名
- 大於小於的排序是按照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) |
~
這些條件使用起來也是比較簡單的,我們應當先搞清楚邏輯再去做一系列的測試。
如上所示,這裡我們直接比較了兩個檔案的新舊,然而我們並沒有確認這連個檔案是否存在,如果沒有存在的話,就可能得到一個錯誤的結果。我們可以使用布林運算子來組合測試:
#複合條件測試
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
五、使用雙小括號和雙方括號
雙小括號:
使用雙小括號來使用高階數學表示式,提供了很多其他程式語言類似的運算子。格式如下:
(( 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的場景還是比較多的。
通過這一篇大致的熟悉了結構化命令中的跳轉語句,還有迴圈語句等者我們去學習呢。下篇預告:for/while/until等迴圈語句的使用。 :)