Shell test命令:條件判斷,檢查某條件是否成立

2020-07-16 10:04:34
test 命令是 Bash 中重要的判斷命令,也是 Shell 指令碼中條件判斷的重要輔助工具。當我們需要讓程式自動判斷哪些事情是成立的時,test 命令就派上用場了。

按照檔案型別進行判斷

根據表 1,我們先來看看 test 可以進行哪些檔案型別的判斷。

表 1 檔案型別判斷
測試選項 作 用
-b 檔案 判斷該檔案是否存在,並且是否為塊裝置檔案(是塊裝置檔案為真)
-c 檔案 判斷該檔案是否存在,並且是否為字元裝置檔案(是字元裝置檔案為真)
-d 檔案 判斷該檔案是否存在,並且是否為目錄檔案(是目錄檔案為真)
-e 檔案 判斷該檔案是否存在(存在為真)
-f 檔案 判斷該檔案是否存在,井且是否為普通檔案(是普通檔案為真)
-L 檔案 判斷該檔案是否存在,並且是否為符號連結檔案(是符號連結檔案為真〉
-p 檔案 判斷該檔案是否存在,並且是否為管道檔案(是管道檔案為真)
-s 檔案 判斷該檔案是否存在,並且是否為非空(非空為真)
-S 檔案 判斷該檔案是否存在,並且是否為通訊端檔案(是通訊端檔案為真〉

光看這張表是完全不知道該怎麼操作的,我們來舉個例子吧。先來判斷一下我們存放指令碼的目錄 /root/sh/ 是否存在,命令如下:

[[email protected] ~]# test -e /root/sh/

這條命令也可以這樣寫:

[[email protected] ~]# [-e /root/sh/]

它們的作用是一樣的,推薦使用"[]"方式。因為在指令碼的條件語句中主要應用這種方式。兩條命令執行完後是沒有任何結果的。不過要注意,如果使用"[]"方式,則在"[]"的內部和資料之間必須使用空格;否則判斷式會報錯。

其實 test 命令就是這樣的,但是我們該如何判斷這條命令的執行是否正確呢?還記得"$?"預定義變數嗎?就是看這個變數的值,如果變數值為 0,則代表 test 判斷為真;如果變數值非 0,則代表 test 判斷為假。例如:

[[email protected] ~]# [-e /root/sh/]
[[email protected] ~]# echo $?
0
#判斷結果為0,/root/sh/目錄是存在的
[[email protected] ~]# [-e /root/test]
[[email protected] ~]# echo $?
1
#在/root/下並沒有test檔案或目錄,所以"$?"的返回值為非0


不過這樣檢視命令的結果非常麻煩,也不直觀。還記得多命令順序執行符"&&"和"||"嗎?我們可以再判斷一下 /root/sh/ 是否是目錄,命令如下:

[[email protected] ~]# [-d /root/sh] && echo "yes"||echo "no"
#第一條判斷命令如果正確執行,則列印"yes"; 否則列印"no"
yes

這樣就直觀多了,不過也並不方便。等我們學習了條件判斷,就會知道 test 判斷到底用在明哩,現在就先這樣吧。

按照檔案許可權進行判斷

test 是非常完善的判斷命令,還可以判斷檔案的許可權,我們通過表 2 來看看。

表 2 檔案許可權判斷
測試選項 作 用
-r 檔案 判斷該檔案是否存在,並且是否擁有讀許可權(有讀許可權為真)
-w 檔案 判斷該檔案是否存在,並且是否擁有寫許可權(有寫許可權為真)
-x 檔案 判斷該檔案是否存在,並且是否擁有執行許可權(有執行許可權為真)
-u 檔案 判斷該檔案是否存在,並且是否擁有SUID許可權(有SUID許可權為真)
-g 檔案 判斷該檔案是否存在,並且是否擁有SG1D許可權(有SGID許可權為真)
-k 檔案 判斷該檔案是否存在,並且是否擁有SBIT許可權(有SBIT許可權為真)

在使用 test 命令判斷許可權時,並不能區分所有者、屬組和其他人。只要檔案擁有許可權,test 判斷就為真,而不能區分哪個使用者身份擁有許可權。比如:

[[email protected] ~]# ll student.txt
-rw-r--r--. 1 root root 97 6月7 07:34 student.txt
[[email protected] ~]# [-w student.txt] && echo "yes"||echo "no"
yes
#判斷檔案是擁有寫許可權的

雖然 student.txt 檔案只有所有者擁有寫許可權,但在用 test 判斷時,是不能區分身份的,只要擁有寫許可權就返回真。

兩個檔案之間進行比較

通過表 3 來看看如何進行兩個檔案之間的比較。

表 3 兩個檔案之間進行比較
測試選項 作 用
檔案 1 -nt檔案 2 判斷檔案1的修改時間是否比檔案2的新(如果新則為真)
檔案 1 *ot檔案 2 判斷檔案1的修改時間是否比檔案2的舊(如果舊則為真)
檔案 1 -ef 檔案 2 判斷檔案1是否和檔案2的inode號一致,可以理解為兩個檔案是否為同一個檔案。這個 判斷用於判斷硬連結是很好的方法

我們一直很苦惱,到底該如何判斷兩個檔案是否是硬連結呢?這時 test 就派上用場了,命令如下:

[[email protected] ~]# ln /root/student.txt /tmp/stu.txt
#建立一個硬連結
[[email protected] ~]# [/root/student.txt -ef/tmp/stu.txt] && echo "yes" || echo "no"
yes
#用test測試一下,果然很有用

兩個整數之間進行比較

通過表 4 來學習一下如何在兩個整數之間進行比較。

表 4 兩個整數之間進行比較
測試選項 作 用
整數1 -eq 整數 2 判斷整數 1 是否和整數 2 相等(相等為真)
整數1 -ne 整數 2 判斷整數 1 是否和整數 2 不相等(不相等為真)
整數1 -gt 整數 2 判斷整數 1 是否大於整數 2 (大於為真)
整數1 -lt 整數 2 判斷整數 1 是否小於整數 2(小於為真)
整數1 -ge 整數 2 判斷整數 1 是否大於等於整數 2 (大於等於為真)
整數1 -le 整數 2 判斷整數 1 是否小於等於整數 2(小於等於為真)

舉個例子:

[[email protected] ~]# [23 -ge 22] && echo "yes"||echo "no"
yes
#判斷23是否大於等於22,當然是了
[[email protected] ~】# [23 -le 22] && echo "yes"||echo "no"
no
#判斷23是否小於等於22,當然不是了

字串判斷

通過表 5 來學習一下字串判斷。

表 5 字串判斷
測試選項 作 用
-z 字串 判斷字串是否為空(為空返回真)
-n 字串 判斷宇符串是否為非空(非空返回真)
字串 1 = 字串 2 判斷字串 1 是否和字串 2 相等(相等返回真)
字串 1 != 字串 2 判斷字串 1 是否和字串 2 不相等(不相等返回真)

舉個例子:

[[email protected] ~]# name=sc
#給name變數賦值
[[email protected] ~]# [-z "$name"] && echo "yes" || echo"no"
no
#判斷name變數是否為空,因為不為空,所以返回no


再來看看如何判斷兩個字串相等,命令如下:

[[email protected] ~]# aa=11
[[email protected] ~]# bb=22
#給變數aa和bb賦值
[[email protected] ~]#["$aa"=="bb"] && echo "yes" || echo "no"
no
#判斷兩個變數的值是否相等,明顯不相等,所以 返回no

多重條件判斷

通過表 6 來看看多重條件判斷是什麼樣子的。

表 6 多重條件判斷
測試選項 作 用
判斷 1 -a 判斷 2 邏輯與,判斷 1 和判斷 2 都成立,最終的結果才為真
判斷 1 -o 判斷 2 邏輯或,判斷 1 和判斷 2 有一個成立,最終的結果就為真
! 判斷 邏輯非,使原始的判斷式取反

舉個例子:

[[email protected] ~]# aa=11
#給變數aa賦值
[[email protected] ~]# [-n "$aa" -a "$aa" -gt 23] && echo "yes" || echo "no"
no
#判斷變數aa是否有值,同時判斷變數aa的值是否大於23
#因為變數aa的值不大於23,所以雖然第一個判斷值為真,但返回的結果是假


要想讓剛剛的判斷式返回真,需要給變數 aa 重新賦一個大於 23 的值,命令如下:

[[email protected] ~]# aa=24
[[email protected] ~]# [-n "$aa" -a "$aa" -gt 23] && echo "yes" || echo "no" yes
 

再來看看邏輯非是什麼樣子的,命令如下:

[[email protected] ~]# [! -n "$aa"] && echo "yes" || echo "no"
no
#本來"-n"選項是變數aa不為空,返回值就是真
#加入"!"之後,判斷值就會取反,所以當變數aa有值時,返回值是假


注意,"!"和"-n"之間必須加入空格,否則會報錯。