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
我是謝恩銘,在巴黎奮鬥的軟體工程師。
我的簡介
我的經歷
熱愛生活,喜歡游泳,略懂烹飪。
人生格言:“向著標杆直跑”

相關文章