SHELL-流程控制
SHELL指令碼-流程控制
1 if-then語句-判斷
1.1 基本結構
if command;then
commands
fi
該結構的if語句可以用於判斷if後的command是否執行成功,當該command執行成功(狀態返回碼為0),則執行then後的語句,否則退出。
if command;then
commands
else
commands
fi
該結構的if語句與上一結構功能類似,只是當command執行不成功的時候,執行else後的語句。
1.2 巢狀if
if command;then
commands
elif command;then
commands
else
commands
fi
這種巢狀的if語句,使用elif用於測試另外的命令,如果if後的command退出狀態碼為非0,則會測試elif後的命令,如果elif後的命令退出狀態碼為0則會執行,elif後的then語句,否則執行else語句。所以緊跟在elif語句的else語句,是屬於elif的程式碼塊,而不是if-then的程式碼塊。
通過將多個elif語句聯合起來,可以形成一個大規模的if-then-elif的巢狀組,從而實現類似於case語句的功能。
if command;then
commands
elif command;then
commands
elif command;then
commands
elif command;then
commands
fi
1.3 if的條件判斷
與其他高階語言相同,if語句不僅可以根據命令的執行狀態進行選擇判斷,也可以通過判斷條件是否成立執行命令。
儘管if語句中的條件判斷可以通過test命令實現,但最常使用的條件判斷方法是使用方括號。
if [ condition ];then commands else commands fi
通過方括號執行條件判斷需要注意的是,在條件判斷語句和方括號左右兩邊均有空格隔開。
1.3.1 數值比較
假定變數 a 為 5,變數 b 為 10:
運算子 | 說明 | 舉例 |
---|---|---|
-eq | 檢測兩個數是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 檢測兩個數是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 檢測左邊的數是否大於右邊的,如果是,則返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 檢測左邊的數是否小於右邊的,如果是,則返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 檢測左邊的數是否大於等於右邊的,如果是,則返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 檢測左邊的數是否小於等於右邊的,如果是,則返回 true。 | [ $a -le $b ] 返回 true。 |
1.3.2 字串比較
下表列出了常用的字串運算子,假定變數 a 為 "abc",變數 b 為 "efg":
運算子 | 說明 | 舉例 |
---|---|---|
= | 檢測兩個字串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 檢測兩個字串是否不相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 檢測字串長度是否為0,為0返回 true。 | [ -z $a ] 返回 false。 |
-n | 檢測字串長度是否不為 0,不為 0 返回 true。 | [ -n "$a" ] 返回 true。 |
$ | 檢測字串是否為空,不為空返回 true。 | [ $a ] 返回 true。 |
1.3.3 檔案比較
操作符 | 說明 | 舉例 |
---|---|---|
-b file | 檢測檔案是否是塊裝置檔案,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-c file | 檢測檔案是否是字元裝置檔案,如果是,則返回 true。 | [ -c $file ] 返回 false。 |
-d file | 檢測檔案是否是目錄,如果是,則返回 true。 | [ -d $file ] 返回 false。 |
-f file | 檢測檔案是否是普通檔案(既不是目錄,也不是裝置檔案),如果是,則返回 true。 | [ -f $file ] 返回 true。 |
-g file | 檢測檔案是否設定了 SGID 位,如果是,則返回 true。 | [ -g $file ] 返回 false。 |
-k file | 檢測檔案是否設定了粘著位(Sticky Bit),如果是,則返回 true。 | [ -k $file ] 返回 false。 |
-p file | 檢測檔案是否是有名管道,如果是,則返回 true。 | [ -p $file ] 返回 false。 |
-u file | 檢測檔案是否設定了 SUID 位,如果是,則返回 true。 | [ -u $file ] 返回 false。 |
-r file | 檢測檔案是否可讀,如果是,則返回 true。 | [ -r $file ] 返回 true。 |
-w file | 檢測檔案是否可寫,如果是,則返回 true。 | [ -w $file ] 返回 true。 |
-x file | 檢測檔案是否可執行,如果是,則返回 true。 | [ -x $file ] 返回 true。 |
-s file | 檢測檔案是否為空(檔案大小是否大於0),不為空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 檢測檔案(包括目錄)是否存在,如果是,則返回 true。 | [ -e $file ] 返回 true。 |
其他檢查符:
- -S: 判斷某檔案是否 socket。
- -L: 檢測檔案是否存在並且是一個符號連結。
1.4 if-then的高階特性
- 通過使用雙方括號不僅可以使用標準的字串比較,也可以通過正則表示式匹配字元。
- 通過使用雙括號可以使用任意的書序賦值或比較表示式,雙括號用到的其他運算子如下表
符號 | 描述 |
---|---|
val++ | 後增 |
val-- | 後減 |
++val | 先增 |
--val | 先減 |
! | 邏輯求反 |
~ | 位求反 |
** | 冪運算 |
<< | 左位移 |
>> | 右位移 |
& | 位布林和 |
| | 位布林或 |
&& | 邏輯和 |
|| | 邏輯或 |
1.5 case 語句
case var in
pattern1)
commands1
;;
pattern2)
commands2
;;
*)
commands3
;;
esac
case語句用於匹配同一變數的不同值,避免了使用if-then-elif的迴圈巢狀導致的邏輯混亂。語法結構更加清晰。
2 for while 迴圈語句
2.1 for語句基本格式
for var in list;do
commands
done
在list引數中,你需要提供迭代中要用到的一系列值。可以通過幾種不同的方法指定列表 中的值。
在每次迭代中,變數var會包含列表中的當前值。第一次迭代會使用列表中的第一個值,第 二次迭代使用第二個值,以此類推,直到列表中的所有值都過一遍。
在do和done語句之間輸入的命令可以是一條或多條標準的bash shell命令。在這些命令中, $var變數包含著這次迭代對應的當前列表項中的值。
list的值可以是數字,也可以是字串。列表的值可以是由自己定義而來的,也可以是命令執行後的結果。常見的幾種迭代定義方法:
#var值由192.168.1.2-192.168.1.150中迴圈迭代
for var in 192.168.1.{2..150}
#var值迭代資料夾/etc/下的所有檔案或目錄(萬用字元方法)
for var in /etc/*
#var值迭代資料夾/etc/下的所有檔案或目錄
for var in $(ls /etc)
#var值迭代1-6
for var in {1..6}
2.2 更改欄位分隔符
for迭代字串的中各個字串的方法是由一個特殊的環境變數IFS定義的,預設的情況下bash shell會將下列字元當做欄位分隔符:
- 空格
- 製表符
- 換行符
可以在shell指令碼中定義IFS的值變更分割符號如IFS=:
在處理程式碼量較大的指令碼時,可能在一個地方需要修改IFS的值,然後忽略這次修改,在
指令碼的其他地方繼續沿用IFS的預設值。一個可參考的安全實踐是在改變IFS之前儲存原
來的IFS值,之後再恢復它。
這種技術可以這樣實現:
IFS.OLD=$IFS
IFS=$'\n'
<在程式碼中使用新的IFS值>
IFS=$IFS.OLD
這就保證了在指令碼的後續操作中使用的是IFS的預設值
2.3 C語言風格的for迴圈
在shell指令碼中可以通過雙括號實現C語言風格的for迴圈,如:for (( i=1; i <= 10; i++ ))
。
for迴圈通過定義好的變數(本例中是變數i)來迭代執行這些命令。在每次迭代中,$i變 量包含了for迴圈中賦予的值。在每次迭代後,迴圈的迭代過程會作用在變數上,在本例中,變 量增一。
也可以同時迭代兩個變數如:for (( a=1, b=10; a <= 10; a++, b-- ))
2.4 while迴圈
while迴圈可以視作某種if-then與for迴圈的混雜體。對while迴圈設定一個跳出迴圈條件,如果不符合條件將一直迴圈下去。設定條件的方式和if-then語句完全一樣。需要注意的是當設定條件的時候,需要明確自己是需要一個死迴圈還是有限迴圈,並根據設計的目的,新增變數迭代方式。
while迴圈的基本結果如:
while test command ;do
other commands
done
通過while ture
可以實現程式碼的死迴圈,當然即使設定死迴圈也需要通過break
設定跳出迴圈的條件。
2.5 until迴圈
until命令和while命令工作的方式完全相反。until命令要求你指定一個通常返回非零退 出狀態碼的測試命令。只有測試命令的退出狀態碼不為0,bash shell才會執行迴圈中列出的命令。 一旦測試命令返回了退出狀態碼0,迴圈就結束了。
until的基本格式如:
untile test command;do
other commands
done
2.6 控制迴圈
你可能會想,一旦啟動了迴圈,就必須苦等到迴圈完成所有的迭代。並不是這樣的。有兩個 命令能幫我們控制迴圈內部的情況:
- break
- continue
break命令可以直接跳出迴圈,不執行剩餘的迭代任務。break預設只跳出一層迴圈,如果有巢狀迴圈的存在,需要跳出多層迴圈,可以通過break n
。n為1,表明跳出的是當前的迴圈(這也是預設設定)。如果你將 n設為2,break命令就會停止下一級的外部迴圈。
continue命令可以提前中止某次迴圈中的命令,但並不會完全終止整個迴圈。在當前迴圈中,剩餘的命令將不會被執行,而直接進入下一次的迴圈。