Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

程式設計師聯盟發表於2019-01-11

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

— 作者 謝恩銘 轉載請註明出處

內容簡介


  1. 前言
  2. if : 最簡單的條件
  3. 條件測試
  4. case : 測試多個條件
  5. 總結
  6. 第五部分第五課預告

1. 前言


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

有個對聯說得好:

「說你行,你就行,不行也行」
「說不行,就不行,行也不行」
「橫批:不服不行」

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

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

小編:為了壓韻,也是蠻拼的…

對於所有程式語言,做決定是很重要的。如果程式設計師不決定程式做什麼,那麼程式只會一直做同樣的事情,就很無趣了。

而條件語句就是用於幫助程式做決定的。在我們的 Shell 指令碼中,條件語句可以做以下「抉擇」:

如果,變數的值等於 xxx ,

那麼,這樣做;

否則,那樣做。複製程式碼

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

即使你沒學過其他程式語言,那也不必擔心,跟著我們學完這課,保證你瞭然於胸。

2. if : 最簡單的條件


最常用的條件語句就是 if 條件語句。

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

if 條件語句的基本格式是這樣的:

if [ 條件測試 ]
then 
    做這個
fi複製程式碼

fi 是 if 的反轉寫法,表示「if 語句結束」。
then 是英語「那麼」的意思。

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

注意:方括號 [] 中的「條件測試」兩邊必須要空一格。不能寫成 [test],而要寫成[ test ]。
唉,Shell 就是這麼任性,你不服都不行!

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

if [ 條件測試 ]; then
    做這個
fi複製程式碼

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

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

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

vim condition.sh複製程式碼

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

#!/bin/bash

name="Enming"

if [ $name = "Enming" ]
then
   echo "Hello $name !"
fi複製程式碼

在 Shell 語言中,「等於」是用一個等號( = )來表示的,這和大多數主流程式語言不同。C語言中「等於」是用兩個等號( == )來表示的。但 Shell 中用兩個等號來表示「等於」的判斷也是可以的。

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

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

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

#!/bin/bash

name1="Enming"
name2="Oscar"

if [ $name1 = $name2 ]
then
   echo "You two have the same name !"
fi複製程式碼

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

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

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

else : 否則


既然有「如果」的條件判斷,那麼也會存在條件不成立的時候,就好比上面那個程式中,「 Enming 」和「 Oscar 」這兩個字串不相同的情況。

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

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

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

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

if [ 條件測試 ]
then
    做這個
else
    做那個
fi複製程式碼

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

我們來看一個例子:

#!/bin/bash

name1="Enming"
name2="Oscar"

if [ $name1 = $name2 ]
then
    echo "You two have the same name !"
else
    echo "You two have different name !"
fi複製程式碼

執行:

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

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

elif : 否則,如果


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

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

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

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

if [ 條件測試 1 ]
then
    做 1 的事情
elif [ 條件測試 2 ]
then
    做 2 的事情
elif [ 條件測試 3 ]
then
    做 3 的事情
else
    做其他事情
fi複製程式碼

我們來看一個例子:

#!/bin/bash

if [ $1 = "Matthew" ]
then
    echo "Hello Matthew !"
elif [ $1 = "Mark" ]
then
    echo "Hello Mark !"
elif [ $1 = "Luke" ]
then
    echo "Hello Luke !"
elif [ $1 = "John" ]
then
    echo "Hello John !"
else
    echo "Sorry, I do not know you."
fi複製程式碼

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

執行:

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

我們可以寫任意多個 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/bash

if [ -z $1 ]
then
    echo "No parameter"
else
    echo "There is parameter"
fi複製程式碼

「 No parameter 」是英語「沒有引數」的意思。
「 There is parameter 」是英語「有引數」的意思。

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

測試數字


儘管 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/bash

if [ $1 -ge 10 ]
then
    echo "You have entered 10 or more"
else
    echo "You have entered less than 10"
fi複製程式碼

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

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

測試檔案


相比於主流程式語言,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/bash

read -p `Enter a directory : ` file

if [ -d $file ]
then
    echo "$file is a directory"
else
    echo "$file is not a directory"
fi複製程式碼

執行:

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

一次測試多個條件


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

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

來看一個例子:

#!/bin/bash

if [ $# -ge 1 ] && [ $1 = `love` ]
then
    echo "Great !"
    echo "You know the password"
else
    echo "You do not know the password"
fi複製程式碼

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

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

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

  1. 引數是否至少有 1 個 ( $# 大於或等於 1 )
  2. 第一個引數是否等於 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/bash

read -p `Enter a file : ` file

if [ ! -e $file ]
then
    echo "$file does not exist"
else
    echo "$file exists"
fi複製程式碼

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

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

執行:

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

4. case : 測試多個條件


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

#!/bin/bash

if [ $1 = "Matthew" ]
then
    echo "Hello Matthew !"
elif [ $1 = "Mark" ]
then
    echo "Hello Mark !"
elif [ $1 = "Luke" ]
then
    echo "Hello Luke !"
elif [ $1 = "John" ]
then
    echo "Hello John !"
else
    echo "Sorry, I do not know you."
fi複製程式碼

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

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

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

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

#!/bin/bash

case $1 in
    "Matthew")
        echo "Hello Matthew !"
        ;;
    "Mark")
        echo "Hello Mark !"
        ;;
    "Luke")
        echo "Hello Luke !"
        ;;
    "John")
        echo "Hello John !"
        ;;
    *)
        echo "Sorry, I do not know you."
        ;;
esac複製程式碼

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

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

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

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

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

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

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

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

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

來看一個例子:

#!/bin/bash

case $1 in
    "dog" | "cat" | "pig")
        echo "It is a mammal"
        ;;
    "pigeon" | "swallow")
        echo "It is a bird"
        ;;
    *)
        echo "I do not know what it is"
        ;;
esac複製程式碼

「 It is a mammal 」是英語「這是一隻哺乳動物」的意思。
「 It is a bird 」是英語「這是一隻鳥」的意思。
「 I do not know what it is 」是英語「我不知道這是什麼」的意思。

執行:

Linux 探索之旅 | 第五部分第四課:條件一出,Shell 不服

5. 總結


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

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

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

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

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

6. 第五部分第五課預告


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

下一課我們學習:Linux探索之旅 | 第五部分第五課:迴圈往復,Shell開路


微信公眾號「程式設計師聯盟」ProgrammerLeague
我是謝恩銘,在巴黎奮鬥的軟體工程師。
我的簡介
我的經歷
熱愛生活,喜歡游泳,略懂烹飪。
人生格言:“向著標杆直跑”

相關文章