1. 程式人生 > 實用技巧 >shell中的邏輯運算/布林運算/短路與/短路或

shell中的邏輯運算/布林運算/短路與/短路或

  參考:http://www.zsythink.net/archives/1154

  

  在瞭解shell中的邏輯運算之前,我們先回顧一下邏輯運算的概念,如下概念引用自"互動百科"。

  什麼是邏輯運算 ? 邏輯運算又稱布林運算,邏輯運算用來判斷一件事情是"對"的還是"錯"的,或者說是"成立"還是"不成立",判斷的結果是二值的,即沒有"可能是"或者"可能不是",這個"可能"的用法是一個模糊概念,在計算機裡面進行的是二進位制運算,邏輯判斷的結果只有二個值,稱這二個值為"邏輯值"("True"或"False"),用數的符號表示就是"1"和"0"。其中"1"表示該邏輯運算的結果是"成立"的,如果一個邏輯運算式的結果為"0",那麼這個邏輯運算式表達的內容"不成立"。

  上述文字引用自互動百科-邏輯運算

  邏輯運算中,最常用的無非就是 "與"、"或" 、"非",我們先聊聊最容易理解的"非"。

  用兩句話概述邏輯運算中的"非":

  非真即假

  非假即真

  shell中,"非"的邏輯運算子為 "!" ,那麼,用邏輯運算公式表示上面的兩句話,如下

  ! true = false

  ! false = true

  "非"是比較容易理解的,在shell中,"與"和"或"有兩種表達方式。

  在shell中,"與"的運算子為"-a",同時,"與"的邏輯運算子也可以用"&&"表示。

  在shell中,"或"的運算子為"-o",同時,"或"的邏輯運算子也可以用"||"表示。

  我們先聊聊"與",我們都知道,當進行與運算時,運算雙方必須同時為真,結果才為真,那麼用公式表示如下。

  true -a true = true

  true -a false = false

  false -a true = false

  false -a false = false

  在上文中已經提到過,"與"還可以用"&&"表示,但是"&&"與"-a"有所不同,"&&"有短路功能,也可以稱為"短路與","&&"與"-a"不僅功能上略有區別,在使用方法上也有不同之處,我們先看看它們在使用方法上有何不同之處。

當使用"&&"或者"-a"作為條件判斷的運算子時,它們的語法略有區別,示例如下:

[root@node1 shell_learn]# if [ 10 -gt 5 -a 10 -gt 9 ];then echo "true";fi
true
[root@node1 shell_learn]# if [[ 10 -gt 5 && 10 -gt 9 ]];then echo "true";fi
true
[root@node1 shell_learn]# if [ 10 -gt 5 ] && [ 10 -gt 9 ];then echo "true";fi
true
[root@node1 shell_learn]# if [[ 10 -gt 5 -a 10 -gt 9 ]];then echo "true";fi
-bash: 條件表示式中有語法錯誤
-bash: `-a' 附近有語法錯誤
[root@node1 shell_learn]# if [ 10 -gt 5 && 10 -gt 9 ];then echo "true";fi
-bash: [: 缺少 `]'
[root@node1 shell_learn]# 

  從上圖可以看出,當使用"&&"或者"-a"作為條件判斷的運算子時,"-a"只能用"單大括號"括起,"&&"只能用"雙大括號"括起,如果使用"雙大括號"括起"-a"或者使用"單大括號"括起"&&",則都會出現語法錯誤。"&&"除了能用"雙大括號"括起,還可以使用"&&"將兩個"單括號括起的條件"連線在一起,效果是相同的。

  從上述描述中,我想我已經說明白了"&&"與"-a"在語法上的不同,現在我們再說說"&&"的短路功能。

  在shell命令列中,每一個命令執行以後,都會返回一個狀態值,這個狀態值如果為0,則表示命令執行成功,即命令執行狀態為true,如果這個狀態值為非0值,則表示命令執行的狀態為false,通過echo $?可以檢視命令執行的狀態值,示例如下。

[root@node1 shell_learn]# cd
[root@node1 ~]# echo $?
0
[root@node1 ~]# cd jkdsahfk
-bash: cd: jkdsahfk: 沒有那個檔案或目錄
[root@node1 ~]# echo $?
1
[root@node1 ~]# 

  從上圖中可以看到,第一條命令執行成功了,而第二條命令執行失敗了,即第一條命令的執行狀態返回值為true,第二條命令的執行狀態返回值為false,其實,我們可以利用命令的狀態返回值以及"&&"的短路特性實現某種功能,比如,cmd1 && cmd2,這個公式表示如果cmd1命令執行成功,則執行cmd2命令,什麼意思呢?我們來看一個示例,如下。

[root@node1 ~]# cd / && echo "cd root dir success"
cd root dir success
[root@node1 /]# cd /asd && echo "cd root dir success"
-bash: cd: /asd: 沒有那個檔案或目錄
[root@node1 /]# 

  從上圖示例中,可以看出,當"&&"之前的命令執行成功時,則執行"&&"之後的命令,當"&&"之前的命令執行失敗時,"&&"之後的命令則不會被執行

  這就是"&&"所謂的短路功能,即如果cmd1的執行結果為true,則必須要執行cmd2,如果cmd1的執行結果為false,cmd2則不會被執行,為什麼會出現這種情況呢?我們之前說過,當進行與運算時,運算雙方必須同時為真,結果才為真,所以,即使cmd1的執行結果為真,也必須得出cmd2的執行結果後,才能判斷出最終進行"與運算"以後的結果是否為真,也就是說,如果cmd1執行結果為真,cmd2執行結果為假,那麼true && false 結果為false,如果cmd1執行結果為真,cmd2執行結果也為真,那麼true && true 結果為true,所以,cmd1的結果為真並不能決定最終進行"與運算"以後的結果是否為真,所以cmd2必須執行,而如果cmd1的執行結果為假,那麼不管cmd2的執行結果為真或是為假,最終進行"與運算"以後得出的結果肯定為假,所以當cmd1執行失敗時,cmd2不會被執行。

  

  聊完了"與",我們再聊聊"或",我們也知道,當進行或運算時,運算雙方只要有一個為真,結果即為真,那麼用公式表示如下。

  true -o true = true

  true -o false = true

  false -o true = true

  false -o false = false

  同樣,在shell中,"-o"表示或,"||"也表示或,但是它們有所不同,之前已經說明了"&&"與"-a"的不同之處,聰明如你一定已經想到,"||"和"-o"的不同之處就是"||"有短路功能,而且它們作為條件判斷的運算子時,語法不同,示例如下。

[root@node1 ~]# if [ 10 -gt 11 -o 10 -gt 9 ];then echo "true";fi
true
[root@node1 ~]# if [[ 10 -gt 11 || 10 -gt 9 ]];then echo "true";fi
true
[root@node1 ~]# if [ 10 -gt 11 || 10 -gt 9 ];then echo "true";fi
-bash: [: 缺少 `]'
-bash: 10: 未找到命令
[root@node1 ~]# if [[ 10 -gt 11 -o 10 -gt 9 ]];then echo "true";fi
-bash: 條件表示式中有語法錯誤
-bash: `-o' 附近有語法錯誤
[root@node1 ~]# if [ 10 -gt 11 ] || [ 10 -gt 9 ];then echo "true";fi
true

  對比之前"&&"的使用方法,就更容易理解了,此處不再贅述,我們主要聊聊"短路或"的用法。因為已經說明了"短路與"的用法,"短路或"就好理解了,我們先回顧一下"短路與"。

  上圖中就利用了"&&"的短路特性,即如果cmd1的執行結果為true,則必須要執行cmd2,如果cmd1的執行結果為false,cmd2則不會被執行。那麼,我們把上圖中的"短路與"改為"短路或",如下圖所示

[root@node1 /]# cd / || echo "cd root dir success"

  從上圖可以發現,cmd1執行成功後,cmd2並沒有被執行,那麼此處,我們故意讓cmd1執行失敗,看看cmd2會不會被執行。

[root@node1 /]# cd /dasd || echo "cd root dir success"
-bash: cd: /dasd: 沒有那個檔案或目錄
cd root dir success
[root@node1 /]# 

  從上圖可以看出,當cmd1執行失敗時,cmd2則會被執行,這就是"短路或"的特性。

  "||"所謂的短路功能,即如果cmd1的執行結果為false,則必須要執行cmd2,如果cmd1的執行結果為true,cmd2則不會被執行,之所以會這樣,是因為在進行"或運算"時,運算雙方只要有一個為真,"或運算"之後肯定為真,所以只要cmd1的執行結果為真,那麼cmd2就不會再被執行了,因為不管cmd2的執行結果為真或為假,或運算的結果肯定為真,但是,如果cmd1的執行結果為假,那麼cmd2則必須被執行,因為如果此時cmd2的執行結果也為假,那麼或運算的結果為假,如果cmd2的執行結果為真,則或運算的執行結果為真,此處對比"短路與"的解釋更容易理解。

  那麼,"短路與"和"短路或"已經解釋完畢,我們似乎已經明白了它們的用法,但是,我們能不能結合它們一起使用呢,必須能啊,示例語法如下。

cmd1 && cmd2 || cmd3

  那麼,上述語法是什麼意思呢?

  上述語法表示,表示如果cmd1執行成功,則執行cmd2,如果cmd1執行失敗,則不執行cmd2,而是執行cmd3。

  這可能與我們"一廂情願"的理解不太一樣,為什麼會出現上述情況呢,我們來詳細解釋一下。

  首先cmd1執行,如果cmd1執行狀態為真,因為&&的緣故,所以cmd2必須執行,因為有&&的情況下是兩個條件同時為真,最終結果才能為真,cmd1執行狀態為真的情況下,cmd2的狀態決定了最終的結果是不是真,如果cmd2的執行狀態也為真 ,那麼 (cmd1 && cmd2)這個整體就是真,又因為||的關係,當(cmd1 && cmd2)這個整體就是真的時候 ,cmd3就不用執行了,因為|| 代表只要有一個條件為真,最終的結果就是真,兩個條件同時為假,最終的結果才為假, 所以(cmd1 && cmd2)這個整體如果是真,那麼結果肯定是真,就不用再考慮cmd3的狀態是否為真了,就不用再執行cmd3了。

  但是如果cmd1的執行狀態為假,(cmd1 && cmd2)這個整體的狀態肯定為假 ,因為&&表示兩個條件中只要有一個條件為假,那麼結果肯定是假,所以當cmd1為假的時候,cmd2就不會再執行了,因為cmd1為假的時候,cmd2的執行狀態並不能影響(cmd1 && cmd2)這個整體的狀態,cmd1執行狀態為假,(cmd1 && cmd2)肯定是假,(cmd1 && cmd2)是假,可是因為 || 的緣故, cmd3必須執行 ,前面已經說過,||表示兩個條件同時為假,最終的結果才是假,因為(cmd1 && cmd2)這個整體是假,所以必須通過cmd3的執行狀態,才能判斷出最終的結果是不是假,所以cmd3必須執行。

  注意:短路或和短路與的順序非常重要,它們的前後順序決定了命令的邏輯。