if-then語句有如下格式:
if command
then
commands
fi
bash shell的if語句會運行if後面的那個命令。如果該命令的退出狀态碼(參見第11章)是0(該命令成功運行),位于then部分的命令就會被執行。如果該命令的退出狀态碼是其他值, then部分的命令就不會被執行,bash shell會繼續執行腳本中的下一個命令。fi語句用來表示if-then語句到此結束。
說明 你可能在有些腳本中看到過if-then語句的另一種形式:
if command; then
commands
fi
通過把分号放在待求值的命令尾部,就可以将then語句放在同一行上了,這樣看起來更像其他編程語言中的if-then語句。
12.2 if-then-else語句
if command
then
commands
else
commands
fi
當if語句中的命令返回退出狀态碼0時,then部分中的命令會被執行,這跟普通的if-then語句一樣。當if語句中的命令返回非零退出狀态碼時,bash shell會執行else部分中的命令。
12.3 嵌套if檢查腳本代碼中的多種條件
要檢查/etc/passwd文件中是否存在某個用戶名以及該用戶的目錄是否尚在,可以使用嵌套的if-then語句。嵌套的if-then語句位于主if-then-else語句的else代碼塊中。
可以使用else部分的另一種形式:elif。這樣就不用再書寫多個if-then語句了。elif使用另一個if-then語句延續else部分。
if command1
then
commands
elif command2
then
more commands
fi
elif語句行提供了另一個要測試的命令,這類似于原始的if語句行。如果elif後命令的退出狀态碼是0,則bash會執行第二個then語句部分的命令。使用這種嵌套方法,代碼更清晰,邏輯更易懂
在elif語句中,緊跟其後的else語句屬于elif代碼塊。它們并不屬于之前的if-then代碼塊
12.4 test命令test命令提供了在if-then語句中測試不同條件的途徑。如果test命令中列出的條件成立,test命令就會退出并返回退出狀态碼0。這樣if-then語句就與其他編程語言中的if-then語句以類似的方式工作了。如果條件不成立,test命令就會退出并返回非零的退出狀态碼,這使得if-then語句不會再被執行。
test命令的格式非常簡單。
test condition
condition是test命令要測試的一系列參數和值。當用在if-then語句中時,test命令看起來是這樣的。
if test condition
then
commands
fi
如果不寫test命令的condition部分,它會以非零的退出狀态碼退出,并執行else語句塊
當你加入一個條件時,test命令會測試該條件。例如,可以使用test命令确定變量中是否有内容。這隻需要一個簡單的條件表達式。
變量my_variable中包含有内容(Full),因此當test命令測試條件時,返回的退出狀态為0。這使得then語句塊中的語句得以執行。
如你所料,如果該變量中沒有包含内容,就會出現相反的情況。
bash shell提供了另一種條件測試方法,無需在if-then語句中聲明test命令。
if [ condition ]
then
commands
fi
方括号定義了測試條件。注意,第一個方括号之後和第二個方括号之前必須加上一個空格,否則就會報錯。
test命令可以判斷三類條件:
數值比較
字符串比較
文件比較
12.4.1 數值比較使用test命令最常見的情形是對兩個數值進行比較
例子:
第一個條件測試:
if [ $value1 -gt 5 ]
測試變量value1的值是否大于5。第二個條件測試:
if [ $value1 -eq $value2 ]
測試變量value1的值是否和變量value2的值相等。兩個數值條件測試的結果和預想一緻。
涉及浮點值時,數值條件測試會有一個限制
此例,變量value1中存儲的是浮點值。接着,腳本對這個值進行了測試。顯然這裡出錯了。
記住,bash shell隻能處理整數。如果你隻是要通過echo語句來顯示這個結果,那沒問題。但是,在基于數字的函數中就不行了,例如我們的數值測試條件。最後一行就說明我們不能在test命令中使用浮點值。
12.4.2 字符串比較1. 字符串相等性
記住,在比較字符串的相等性時,比較測試會将所有的标點和大小寫情況都考慮在内。
2. 字符串順序要測試一個字符串是否比另一個字符串大就是麻煩的開始。當要開始使用測試條件的大于或小于功能時,就會出現兩個經常困擾shell程序員的問題:
大于号和小于号必須轉義,否則shell會把它們當作重定向符号,把字符串值當作文件名;
大于和小于順序和sort命令所采用的不同。
這個腳本中隻用了大于号,沒有出現錯誤,但結果是錯的。腳本把大于号解釋成了輸出重定向。因此,它創建了一個名為hockey的文件。由于重定向的順利完成,test命令返回了退出狀态碼0,if語句便以為所有命令都成功結束了。
要解決這個問題,就需要正确轉義大于号。
第二個問題更細微,除非你經常處理大小寫字母,否則幾乎遇不到。sort命令處理大寫字母的方法剛好跟test命令相反。
在比較測試中,大寫字母被認為是小于小寫字母的。但sort命令恰好相反。當你将同樣的字符串放進文件中并用sort命令排序時,小寫字母會先出現。這是由各個命令使用的排序技術不同造成的
比較測試中使用的是标準的ASCII順序,根據每個字符的ASCII數值來決定排序結果(字母A比字母Z要小,并按A到Z順序遞增。同個字母的大寫字母比小寫字母要小32)。
sort命令使用的是系統的本地化語言設置中定義的排序順序。對于英語,本地化設置指定了在排序順序中小寫字母出現在大寫字母前。
test命令和測試表達式使用标準的數學比較符号來表示字符串比較,而用文本代碼來表示數值比較。這個細微的特性被很多程序員理解反了。如果你對數值使用了數學運算符号,shell會将它們當成字符串值,可能無法得到正确的結果。
字符串比較用/> 數字比較用-gt
3. 字符串大小-n和-z可以檢查一個變量是否含有數據。
這個例子創建了兩個字符串變量。val1變量包含了一個字符串,val2變量包含的是一個空字符串。後續的比較如下:
if [ -n $val1 ] 判斷val1變量是否長度非0,而它的長度正好非0,所以then部分被執行了。
if [ -z $var2 ] 判斷val2變量是否長度為0,而它正好長度為0,所以then部分被執行了。
if [ -z $val3 ] 判斷val3變量是否長度為0。這個變量并未在shell腳本中定義過,所以它的字符串長度仍然為0,盡管它未被定義過。
空的和未初始化的變量會對shell腳本測試造成災難性的影響。如果不是很确定一個變量的内容,最好在将其用于數值或字符串比較之前先通過-n或-z來測試一下變量是否含有值。
12.4.3 文件比較最後一類比較測試很有可能是shell編程中最為強大、也是用得最多的比較形式。它允許你測試Linux文件系統上文件和目錄的狀态
1. 檢查目錄
-d測試會檢查指定的目錄是否存在于系統中。如果你打算将文件寫入目錄或是準備切換到某個目錄中,先進行測試總是件好事情。
示例代碼中使用了-d測試條件來檢查jump_directory變量中的目錄是否存在:若存在,就使用cd命令切換到該目錄并列出目錄中的内容;若不存在,腳本就輸出一條警告信息,然後退出。
2. 檢查對象是否存在-e比較允許你的腳本代碼在使用文件或目錄前先檢查它們是否存在。
第一次檢查用-e比較來判斷用戶是否有$HOME目錄。如果有,接下來的-e比較會檢查sentinel文件是否存在于$HOME目錄中。如果不存在,shell腳本就會提示該文件不存在,不需要進行更新。
為确保更新操作能夠正常進行,我們創建了sentinel文件,然後重新運行這個shell腳本。這一次在進行條件測試時,$HOME和sentinel文件都存在,因此當前日期和時間就被追加到了文件中。
3. 檢查文件-e比較可用于文件和目錄。要确定指定對象為文件,必須用-f比較。
這一小段腳本進行了大量的檢查!它首先使用-e比較測試$HOME是否存在。如果存在,繼續用-f來測試它是不是一個文件。如果它不是文件(當然不會是了),就會顯示一條消息,表明這不是一個文件。
我們對變量item_name作了一個小小的修改,将目錄$HOME替換成文件$HOME/sentinel,結果就不一樣了。
這裡隻列出了腳本test13.sh的部分代碼,因為隻改變了腳本變量item_name的值。當運行這個腳本時,對$HOME/sentinel進行的-f測試所返回的退出狀态碼為0,then語句得以執行,然後輸出消息:Yes, /home/Christine/sentinel is a file。
4. 檢查是否可讀在嘗試從文件中讀取數據之前,最好先測試一下文件是否可讀。可以使用-r比較測試。
/etc/shadow文件含有系統用戶加密後的密碼,所以它對系統上的普通用戶來說是不可讀的。-r比較确定該文件不允許進行讀取,因此測試失敗,bash shell執行了if-then語句的else部分。
5. 檢查空文件應該用-s比較來檢查文件是否為空,尤其是在不想删除非空文件的時候。要留心的是,當-s比較成功時,說明文件中有數據。
-f比較測試首先測試文件是否存在。如果存在,由-s比較來判斷該文件是否為空。空文件會被删除。可以從ls –l的輸出中看出sentinel并不是空文件,因此腳本并不會删除它。
6. 檢查是否可寫-w比較會判斷你對文件是否有可寫權限。腳本test16.sh隻是腳本test13.sh的修改版。現在不單檢查item_name是否存在、是否為文件,還會檢查該文件是否有寫入權限。
變量item_name被設置成$HOME/sentinel,該文件允許用戶進行寫入。因此當腳本運行時,-w測試表達式會返回零退出狀态,然後執行then代碼塊,将時間戳寫入文件sentinel中。
如果使用chmod關閉文件sentinel的用戶 寫入權限,-w測試表達式會返回非零的退出狀态碼,時間戳不會被寫入文件。
7. 檢查文件是否可以執行-x比較是判斷特定文件是否有執行權限的一個簡單方法。雖然可能大多數命令用不到它,但如果你要在shell腳本中運行大量腳本,它就能發揮作用。
這段示例shell腳本用-x比較來測試是否有權限執行test16.sh腳本。如果有權限,它會運行這個腳本。在首次成功運行test16.sh腳本後,更改文件的權限。這次,-x比較失敗了,因為你已經沒有test16.sh腳本的執行權限了。
8. 檢查所屬關系-O比較可以測試出你是否是文件的屬主。
這段腳本用-O比較來測試運行該腳本的用戶是否是/etc/passwd文件的屬主。這個腳本是運行在普通用戶賬戶下的,所以測試失敗了。
9. 檢查默認屬組關系-G比較會檢查文件的默認組,如果它匹配了用戶的默認組,則測試成功。由于-G比較隻會檢查默認組而非用戶所屬的所有組,這會叫人有點困惑。這裡有個例子。
第一次運行腳本時,$HOME/testing文件屬于rich組,所以通過了-G比較。接下來,組被改成了sharing組,用戶也是其中的一員。但是,-G比較失敗了,因為它隻比較默認組,不會去比較其他的組。
10. 檢查文件日期最後一組方法用來對兩個文件的創建日期進行比較。
-nt比較會判定一個文件是否比另一個文件新。如果文件較新,那意味着它的文件創建日期更近。
-ot比較會判定一個文件是否比另一個文件舊。如果文件較舊,意味着它的創建日期更早。
用于比較文件路徑是相對你運行該腳本的目錄而言的。如果你要檢查的文件已經移走,就會出現問題。另一個問題是,這些比較都不會先檢查文件是否存在
這個小例子演示了如果文件不存在,-nt比較會返回一個錯誤的結果。在你嘗試使用-nt或-ot比較文件之前,必須先确認文件是存在的。
12.5 複合條件測試if-then語句允許你使用布爾邏輯來組合測試。有兩種布爾運算符可用:
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
第一種布爾運算使用AND布爾運算符來組合兩個條件。要讓then部分的命令執行,兩個條件都必須滿足。
第二種布爾運算使用OR布爾運算符來組合兩個條件。如果任意條件為TRUE,then部分的命令就會執行。
布爾邏輯是一種能夠将可能的返回值簡化為TRUE或FALSE的方法。
使用AND布爾運算符時,兩個比較都必須滿足。第一個比較會檢查用戶的$HOME目錄是否存在。第二個比較會檢查在用戶的$HOME目錄是否有個叫testing的文件,以及用戶是否有該文件的寫入權限。如果兩個比較中的一個失敗了,if語句就會失敗,shell就會執行else部分的命令。如果兩個比較都通過了,則if語句通過,shell會執行then部分的命令。
12.6 if-then的高級特性bash shell提供了兩項可在if-then語句中使用的高級特性:
用于數學表達式的雙括号
用于高級字符串處理功能的雙方括号
12.6.1 使用雙括号 (數學表達式)雙括号命令允許你在比較過程中使用高級數學表達式。test命令隻能在比較中使用簡單的算術操作。雙括号命令提供了更多的數學符号,這些符号對于用過其他編程語言的程序員而言并不陌生。雙括号命令的格式如下:
(( expression ))
expression可以是任意的數學賦值或比較表達式。除了test命令使用的标準數學運算符,表12-4列出了雙括号命令中會用到的其他運算符。
可以在if語句中用雙括号命令,也可以在腳本中的普通命令裡使用來賦值。
注意,不需要将雙括号中表達式裡的大于号轉義。這是雙括号命令提供的另一個高級特性。
12.6.2 使用雙方括号(字符串比較)雙方括号命令提供了針對字符串比較的高級特性。雙方括号命令的格式如下:
[[ expression ]]
雙方括号裡的expression使用了test命令中采用的标準字符串比較。但它提供了test命令未提供的另一個特性——模式匹配(pattern matching)。
雙方括号在bash shell中工作良好。不過要小心,不是所有的shell都支持雙方括号。
在模式匹配中,可以定義一個正則表達式來匹配字符串值。
在上面的腳本中,我們使用了雙等号(==)。雙等号将右邊的字符串(r*)視為一個模式,并應用模式匹配規則。雙方括号命令$USER環境變量進行匹配,看它是否以字母r開頭。如果是的話,比較通過,shell會執行then部分的命令。
12.7 case命令有了case命令,就不需要再寫出所有的elif語句來不停地檢查同一個變量的值了。case命令會采用列表格式來檢查單個變量的多個值
case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac
case命令會将指定的變量與不同模式進行比較。如果變量和模式是匹配的,那麼shell會執行為該模式指定的命令。可以通過豎線操作符在一行中分隔出多個模式模式。星号會捕獲所有與已知模式不匹配的值。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!