參考: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必須執行。
注意:短路或和短路與的順序非常重要,它們的前后順序決定了命令的邏輯。