華文網

Linux探索之旅|第五部分第四課:Shell 條件陳述式

內容簡介

前言

if : 最簡單的條件

條件測試

case : 測試多個條件

總結

第五部分第五課預告

1. 前言

上一課 Linux探索之旅 | 第五部分第三課:變數在手,Shell不愁 有不少內容,這一課我們輕鬆一下,來聊聊條件陳述式。

有個對聯說得好:

「說你行,你就行,不行也行」

「說不行,就不行,行也不行」

「橫批:不服不行」

因此「條件一出,Shell 不服不行」。

讀者:小編你這是什麼邏輯?我們地球人表示不理解... 我看你還是回火星比較好。

小編:為了押韻,也是蠻拼的...

對於所有程式設計語言,

做決定是很重要的。如果程式師不決定程式做什麼,那麼程式只會一直做同樣的事情,就很無趣了。

而條件陳述式就是用於説明程式做決定的。在我們的 Shell 腳本中,條件陳述式可以做以下「抉擇」:

如果,變數的值等於 xxx ,

如果你學過某一門程式設計語言,例如 C 語言 ( 歡迎學習我的 C語言探索之旅 ),那麼對於條件陳述式的原理應該很熟悉了。

即使你沒學過其他程式設計語言,

那也不必擔心,跟著我們學完這課,保證你了然於胸。

2. if : 最簡單的條件

最常用的條件陳述式就是 if 條件陳述式。

if 是英語「如果」的意思。

if 條件陳述式的基本格式是這樣的:

if [ 條件測試 ]then

fi 是 if 的反轉寫法,表示「if 語句結束」。

then 是英語「那麼」的意思。

「做這個」只有在「條件測試」為真時,才會被執行。

注意:方括號 [] 中的「條件測試」兩邊必須要空一格。不能寫成 [test],而要寫成[ test ]。

唉,Shell 就是這麼任性,你不服都不行!

當然了,

if 語句的基本寫法還有一種,那就是把 then 寫在 if [ 條件測試 ] 後面,如下:

if [ 條件測試 ]; then

用這種寫法時,在 if 條件判斷和 then 之間要加一個分號。

我們寫 Shell 程式時,需要把「條件測試」換成我們真實要測試的條件,一般來說都是測試變數的值。

我們可以通過例子來學習,首先創建一個叫做 condition.sh 的檔( condition 是英語「條件」的意思)。

vim condition.sh

然後在裡面輸入以下內容:

#!/bin/bashname="Enming"if [ $name = "Enming" ]then

在 Shell 語言中,「等於」是用一個等號( = )來表示的,這和大多數主流程式設計語言不同。

C語言中「等於」是用兩個等號( == )來表示的。但 Shell 中用兩個等號來表示「等於」的判斷也是可以的。

上例中,因為變數 name 的值等於 "Enming",因此會輸出 「Hello Enming !」

當然了,我們也可以測試兩個變數,例如:

#!/bin/bashname1="Enming"name2="Oscar"if [ $name1 = $name2 ]then

「 You two have the same name 」是英語「你們倆有相同的名字」的意思。

運行上面的程式,可以看到什麼也沒有顯示,因為「 Enming 」和「 Oscar 」這兩個字串不相同。

else : 否則

既然有「如果」的條件判斷,那麼也會存在條件不成立的時候,就好比上面那個程式中,

「 Enming 」和「 Oscar 」這兩個字串不相同的情況。

我們已經知道表示「如果」的關鍵字是 if,那麼表示「否則」的關鍵字應該就是 「else」咯?

沒錯。因為 else 就是英語「否則」的意思。

所以學好英語對於程式設計幫助極大:對於程式師, 為什麼英語比數學更重要? 如何學習 。

因此,if 和 else 兩者配合的邏輯是這樣的:

if [ 條件測試 ]then

也就是:如果「條件測試」為真,那麼「做這個」被執行;否則,「做那個」被執行。

我們來看一個例子:

#!/bin/bashname1="Enming"name2="Oscar"if [ $name1 = $name2 ]then

運行:

「 You two have different name 」是英語「你們有不同的名字」的意思。

elif : 否則,如果

一般來說 if 和 else 已經能滿足我們的大部分條件判斷需要了,但有些時候,存在好幾種情況。

光是 if 和 else 表示的兩種對立的情況已經不足以滿意要求了,因此我們再來學習一個關鍵字:elif 。

elif 是 「 else if 」的縮寫,表示「否則 - 如果」。

if, elif 和 else 三者配合的邏輯是這樣的:

if [ 條件測試 1 ]then

我們來看一個例子:

#!/bin/bashif [ $1 = "Matthew" ]then

「 Sorry, I do not know you 」是英語「對不起,我不認識你」的意思。

運行:

我們可以寫任意多個 elif 語句,但是 if 語句必須要有且只能有一個,else 語句最多只能有一個。

我們可以有單獨由 if 語句組成的條件陳述式,也可以有「 if ... else ... 」組成的條件陳述式,也可以有「 if ... elif ... else... 」組成的條件陳述式,也可以有「 if ... elif ... 」組成的語句。

3. 條件測試

現在我們來看看我們都能做哪些「條件測試」。

之前的例子,我們只比較了字串,但其實我們遠可以做比這更複雜的條件測試。

不同的測試類型

在 bash 中我們可以做三種測試:

測試字串

測試數位

測試檔

我們通過例子一一來學習。

測試字串

我們之前的課程已經說過:在 Shell 中,所有的變數都是字串。

因此,要做字串的測試非常簡單。記住以下表格:

條件意義$string1 = $string2兩個字串是否相等。Shell 大小寫敏感,因此 A 和 a 是不一樣的。$string1 != $string2兩個字串是否不同。-z $string字串 string 是否為空。z是 zero 的首字母,是英語「零」的意思。-n $string字串 string 是否不為空。n 是英語 not 的首字母,是英語「不」的意思。

例如:

#!/bin/bashif [ -z $1 ]then

「 No parameter 」是英語「沒有參數」的意思。

「 There is parameter 」是英語「有參數」的意思。

測試數字

儘管 Shell 把所有變數都看成字串,但是我們還是可以做數字的條件測試。記住以下表格:

條件意義$num1 -eq $num2兩個數字是否相等。和判斷字串所用的符號( = )不一樣。eq 是 equal 的縮寫,是英語「等於」的意思。$num1 -ne $num2兩個數位是否不同。ne 是 not equal 的縮寫,是英語「不等於」的意思。$num1 -lt $num2數字 num1 是否小於 num2。lt 是 lower than 的縮寫,是英語「小於」的意思。$num1 -le $num2數字 num1 是否小於或等於 num2。le 是 lower or equal 的縮寫,是英語「小於或等於」的意思。$num1 -gt $num2數字 num1 是否大於 num2。gt 是 greater than 的縮寫,是英語「大於」的意思。$num1 -ge $num2數字 num1 是否大於或等於 num2。ge 是 greater or equal 的縮寫,是英語「大於或等於」的意思。

看一個例子:

#!/bin/bashif [ $1 -ge 10 ]then

「 You have entered 10 or more 」是英語「你的輸入等於 10 或比 10 更大」的意思。

「 You have entered less than 10 」是英語「你的輸入小於 10」的意思。

測試檔

相比於主流程式設計語言,Shell 的一大優勢就是可以非常方便地測試檔:文件存在嗎?我們可以寫入檔嗎?這個檔比那個檔修改時間更早還是更晚?等等。

下表非常豐富:

條件意義-e $file檔是否存在。e 是 exist 的首字母,表示「存在」。-d $file檔是否是一個目錄。因為 Linux 中所有都是檔,目錄也是檔的一種。d 是 directory 的首字母,表示「目錄」。-f $file檔是否是一個檔。f 是 file 的首字母,表示「檔」。-L $file檔是否是一個符號連結檔。L 是 link 的首字母,表示「連結」。-r $file檔是否可讀。r 是 readable 的首字母,表示「可讀的」。-w $file檔是否可寫。w 是 writable 的首字母,表示「可寫的」。-x $file檔是否可執行。x 是 executable 的首字母,表示「可執行的」。$file1 -nt $file2檔 file1 是否比 file2 更新。nt 是 newer than 的縮寫,表示「更新的」。$file1 -ot $file2檔 file1 是否比 file2 更舊。ot 是 older than 的縮寫,表示「更舊的」。

來看一個例子:

#!/bin/bashread -p 'Enter a directory : ' fileif [ -d $file ]then

運行:

一次測試多個條件

在一個條件測試中,我們可以同時測試多個條件。需要用到兩種符號:

符號意義&&兩個&。表示「邏輯與」。此符號兩端的條件必須全為真,整個條件測試才為真;只要有一個不為真,整個條件測試為假。II兩個分隔號。表示「邏輯或」。此符號兩端的條件只要有一個為真,整個條件測試就為真;只有兩個都為假,整個條件測試才為假。

來看一個例子:

#!/bin/bashif [ $# -ge 1 ] && [ $1 = 'love' ]then

「 Great ! You know the password 」是英語「好極了!你知道密碼」的意思。

「 You do not know the password 」是英語「你不知道密碼」的意思。

上面的測試檢驗了兩個條件:

參數是否至少有 1 個 ( $# 大於或等於 1 )

第一個參數是否等於 love( $1 是否等於 love )

在做多個條件的判斷時,是按照從左到右的順序判斷的,如果前一個條件已經足以決定整個條件測試的真或假,那麼後面的條件就不會被判斷。

例如 [ 2 -ge 1 ] || [ 3 -gt 2 ] 中,2 是大於等於 1 的,因此,「 2 -ge 1 」已經為真,整個條件陳述式肯定為真,「 3 -gt 2 」就不需要被判斷了。

而 [ 2 -ge 4 ] && [ 5 -gt 2 ] 中,2 是小於 4 的,因此,「 2 -ge 4 」已經為假,整個條件陳述式肯定為假,「 5 -gt 2 」就不需要被判斷了。

反轉測試

我們可以用「否定」來反轉測試條件,要用到感嘆號( ! )。

來看一個例子:

#!/bin/bashread -p 'Enter a file : ' fileif [ ! -e $file ]then

條件測試中我們寫了 「 ! -e $file 」,表示「如果檔 file 不存在」。

exist 是英語「存在」的意思。

運行:

4. case : 測試多個條件

之前,我們寫過一個例子,用來演示多個條件測試的情況:

#!/bin/bashif [ $1 = "Matthew" ]then

這個程式當然沒有錯,但是它只對同一個變數做測試(我們輸入的參數 1),卻用了這麼多 elif... then... 未免略顯繁瑣,也不是很好理解。

像這樣的情況,我們可以用 case 語句來實現。

case 是英語「情況」的意思。

我們上面的程式可以改寫成這樣:

#!/bin/bashcase $1 in

運行之後與之前的程式效果一樣。

來分析一下上面的程式。因為有很多新的內容:

case $1 in :$1 表示我們要測試的變數是輸入的第一個參數。in 是英語「在...之中」的意思。

"Matthew") :測試其中一個 case,也就是 $1 是否等於 "Matthew"。當然,我們也可以用星號來做萬用字元來匹配多個字元,例如 "M*") 可以匹配所有以 M 開頭的字串。

;; :類似於主流程式設計語言中的 「 break; 」,表示結束 case 的讀取,程式跳轉到 esac 後面執行。

*) :相當於 if 條件陳述式的 else,表示「否則」,就是「假如不等於上面任何一種情況」。

esac :是 case 的反寫,表示 case 語句的結束。

其實 case 語句就相當於主流程式設計語言中的 switch 語句。

我們也可以在case 語句的匹配項中做「或」的匹配,但是不是用兩個分隔號(邏輯或)了,而是用一個分隔號。

來看一個例子:

#!/bin/bashcase $1 in

「 It is a mammal 」是英語「這是一隻哺乳動物」的意思。

「 It is a bird 」是英語「這是一隻鳥」的意思。

「 I do not know what it is 」是英語「我不知道這是什麼」的意思。

運行:

5. 總結

我們可以用下面的語法來做條件測試:「 if, then, [ [ elif, then, fi ] else, ] fi 」。

我們可以測試字串,也可以測試數位,也可以測試檔。例如文件存在嗎?檔是否可執行?等等。

如果需要,我們可以綜合好幾種測試,用 && (邏輯與),|| (邏輯非)符號。

感嘆號( ! )表示條件「否」,用於反轉條件測試。

當我們對同一個變數做好多測試時,一般用 case 語句比 if 語句更直觀。

6. 第五部分第五課預告

今天的課就到這裡,一起加油吧!

下一課我們學習:循環往復,Shell開路

我是[謝恩銘](http://www.jianshu.com/u/44339a8a9afa),在巴黎奮鬥的軟體工程師。

[我的簡介](http://www.jianshu.com/p/e1c5835fee7d)

[我的經歷](http://www.jianshu.com/p/86c2cfe3b390)

熱愛生活,喜歡游泳,略懂烹飪。

人生格言:“向著標杆直跑”

「 You two have different name 」是英語「你們有不同的名字」的意思。

elif : 否則,如果

一般來說 if 和 else 已經能滿足我們的大部分條件判斷需要了,但有些時候,存在好幾種情況。

光是 if 和 else 表示的兩種對立的情況已經不足以滿意要求了,因此我們再來學習一個關鍵字:elif 。

elif 是 「 else if 」的縮寫,表示「否則 - 如果」。

if, elif 和 else 三者配合的邏輯是這樣的:

if [ 條件測試 1 ]then

我們來看一個例子:

#!/bin/bashif [ $1 = "Matthew" ]then

「 Sorry, I do not know you 」是英語「對不起,我不認識你」的意思。

運行:

我們可以寫任意多個 elif 語句,但是 if 語句必須要有且只能有一個,else 語句最多只能有一個。

我們可以有單獨由 if 語句組成的條件陳述式,也可以有「 if ... else ... 」組成的條件陳述式,也可以有「 if ... elif ... else... 」組成的條件陳述式,也可以有「 if ... elif ... 」組成的語句。

3. 條件測試

現在我們來看看我們都能做哪些「條件測試」。

之前的例子,我們只比較了字串,但其實我們遠可以做比這更複雜的條件測試。

不同的測試類型

在 bash 中我們可以做三種測試:

測試字串

測試數位

測試檔

我們通過例子一一來學習。

測試字串

我們之前的課程已經說過:在 Shell 中,所有的變數都是字串。

因此,要做字串的測試非常簡單。記住以下表格:

條件意義$string1 = $string2兩個字串是否相等。Shell 大小寫敏感,因此 A 和 a 是不一樣的。$string1 != $string2兩個字串是否不同。-z $string字串 string 是否為空。z是 zero 的首字母,是英語「零」的意思。-n $string字串 string 是否不為空。n 是英語 not 的首字母,是英語「不」的意思。

例如:

#!/bin/bashif [ -z $1 ]then

「 No parameter 」是英語「沒有參數」的意思。

「 There is parameter 」是英語「有參數」的意思。

測試數字

儘管 Shell 把所有變數都看成字串,但是我們還是可以做數字的條件測試。記住以下表格:

條件意義$num1 -eq $num2兩個數字是否相等。和判斷字串所用的符號( = )不一樣。eq 是 equal 的縮寫,是英語「等於」的意思。$num1 -ne $num2兩個數位是否不同。ne 是 not equal 的縮寫,是英語「不等於」的意思。$num1 -lt $num2數字 num1 是否小於 num2。lt 是 lower than 的縮寫,是英語「小於」的意思。$num1 -le $num2數字 num1 是否小於或等於 num2。le 是 lower or equal 的縮寫,是英語「小於或等於」的意思。$num1 -gt $num2數字 num1 是否大於 num2。gt 是 greater than 的縮寫,是英語「大於」的意思。$num1 -ge $num2數字 num1 是否大於或等於 num2。ge 是 greater or equal 的縮寫,是英語「大於或等於」的意思。

看一個例子:

#!/bin/bashif [ $1 -ge 10 ]then

「 You have entered 10 or more 」是英語「你的輸入等於 10 或比 10 更大」的意思。

「 You have entered less than 10 」是英語「你的輸入小於 10」的意思。

測試檔

相比於主流程式設計語言,Shell 的一大優勢就是可以非常方便地測試檔:文件存在嗎?我們可以寫入檔嗎?這個檔比那個檔修改時間更早還是更晚?等等。

下表非常豐富:

條件意義-e $file檔是否存在。e 是 exist 的首字母,表示「存在」。-d $file檔是否是一個目錄。因為 Linux 中所有都是檔,目錄也是檔的一種。d 是 directory 的首字母,表示「目錄」。-f $file檔是否是一個檔。f 是 file 的首字母,表示「檔」。-L $file檔是否是一個符號連結檔。L 是 link 的首字母,表示「連結」。-r $file檔是否可讀。r 是 readable 的首字母,表示「可讀的」。-w $file檔是否可寫。w 是 writable 的首字母,表示「可寫的」。-x $file檔是否可執行。x 是 executable 的首字母,表示「可執行的」。$file1 -nt $file2檔 file1 是否比 file2 更新。nt 是 newer than 的縮寫,表示「更新的」。$file1 -ot $file2檔 file1 是否比 file2 更舊。ot 是 older than 的縮寫,表示「更舊的」。

來看一個例子:

#!/bin/bashread -p 'Enter a directory : ' fileif [ -d $file ]then

運行:

一次測試多個條件

在一個條件測試中,我們可以同時測試多個條件。需要用到兩種符號:

符號意義&&兩個&。表示「邏輯與」。此符號兩端的條件必須全為真,整個條件測試才為真;只要有一個不為真,整個條件測試為假。II兩個分隔號。表示「邏輯或」。此符號兩端的條件只要有一個為真,整個條件測試就為真;只有兩個都為假,整個條件測試才為假。

來看一個例子:

#!/bin/bashif [ $# -ge 1 ] && [ $1 = 'love' ]then

「 Great ! You know the password 」是英語「好極了!你知道密碼」的意思。

「 You do not know the password 」是英語「你不知道密碼」的意思。

上面的測試檢驗了兩個條件:

參數是否至少有 1 個 ( $# 大於或等於 1 )

第一個參數是否等於 love( $1 是否等於 love )

在做多個條件的判斷時,是按照從左到右的順序判斷的,如果前一個條件已經足以決定整個條件測試的真或假,那麼後面的條件就不會被判斷。

例如 [ 2 -ge 1 ] || [ 3 -gt 2 ] 中,2 是大於等於 1 的,因此,「 2 -ge 1 」已經為真,整個條件陳述式肯定為真,「 3 -gt 2 」就不需要被判斷了。

而 [ 2 -ge 4 ] && [ 5 -gt 2 ] 中,2 是小於 4 的,因此,「 2 -ge 4 」已經為假,整個條件陳述式肯定為假,「 5 -gt 2 」就不需要被判斷了。

反轉測試

我們可以用「否定」來反轉測試條件,要用到感嘆號( ! )。

來看一個例子:

#!/bin/bashread -p 'Enter a file : ' fileif [ ! -e $file ]then

條件測試中我們寫了 「 ! -e $file 」,表示「如果檔 file 不存在」。

exist 是英語「存在」的意思。

運行:

4. case : 測試多個條件

之前,我們寫過一個例子,用來演示多個條件測試的情況:

#!/bin/bashif [ $1 = "Matthew" ]then

這個程式當然沒有錯,但是它只對同一個變數做測試(我們輸入的參數 1),卻用了這麼多 elif... then... 未免略顯繁瑣,也不是很好理解。

像這樣的情況,我們可以用 case 語句來實現。

case 是英語「情況」的意思。

我們上面的程式可以改寫成這樣:

#!/bin/bashcase $1 in

運行之後與之前的程式效果一樣。

來分析一下上面的程式。因為有很多新的內容:

case $1 in :$1 表示我們要測試的變數是輸入的第一個參數。in 是英語「在...之中」的意思。

"Matthew") :測試其中一個 case,也就是 $1 是否等於 "Matthew"。當然,我們也可以用星號來做萬用字元來匹配多個字元,例如 "M*") 可以匹配所有以 M 開頭的字串。

;; :類似於主流程式設計語言中的 「 break; 」,表示結束 case 的讀取,程式跳轉到 esac 後面執行。

*) :相當於 if 條件陳述式的 else,表示「否則」,就是「假如不等於上面任何一種情況」。

esac :是 case 的反寫,表示 case 語句的結束。

其實 case 語句就相當於主流程式設計語言中的 switch 語句。

我們也可以在case 語句的匹配項中做「或」的匹配,但是不是用兩個分隔號(邏輯或)了,而是用一個分隔號。

來看一個例子:

#!/bin/bashcase $1 in

「 It is a mammal 」是英語「這是一隻哺乳動物」的意思。

「 It is a bird 」是英語「這是一隻鳥」的意思。

「 I do not know what it is 」是英語「我不知道這是什麼」的意思。

運行:

5. 總結

我們可以用下面的語法來做條件測試:「 if, then, [ [ elif, then, fi ] else, ] fi 」。

我們可以測試字串,也可以測試數位,也可以測試檔。例如文件存在嗎?檔是否可執行?等等。

如果需要,我們可以綜合好幾種測試,用 && (邏輯與),|| (邏輯非)符號。

感嘆號( ! )表示條件「否」,用於反轉條件測試。

當我們對同一個變數做好多測試時,一般用 case 語句比 if 語句更直觀。

6. 第五部分第五課預告

今天的課就到這裡,一起加油吧!

下一課我們學習:循環往復,Shell開路

我是[謝恩銘](http://www.jianshu.com/u/44339a8a9afa),在巴黎奮鬥的軟體工程師。

[我的簡介](http://www.jianshu.com/p/e1c5835fee7d)

[我的經歷](http://www.jianshu.com/p/86c2cfe3b390)

熱愛生活,喜歡游泳,略懂烹飪。

人生格言:“向著標杆直跑”