好不容易,進入了兩位數的章節(jié)了... 一路走來,很辛苦吧?也很快樂吧? ^_^
在解答本章題目之前,先讓我們了解一個概念: return value。
我們在 shell 下跑的每一個 command 或 function, 在結束的時候都會傳回父進程一個值,稱為 return value。
在 shell command line 中可用$?, 這個變量得到最 "新" 的一個return value, 也就是剛剛結束的那個進程傳回的值。
Return Value(RV) 的取值為 0-255 之間, 由進程或者 script 的作者自行定義:
若在 script 里,用 exit RV 來指定其值; 若沒有指定, 在結束時,以最后一個命令的 RV,為 script 的 RV 值。
Return Value的作用:用來判斷進程的退出狀態(tài) (exit status)。 進程的退出狀態(tài)有兩種:
舉個例子來說明好了: 假設當前目錄內有一個 my.file 的文件, 而 no.file 是不存在的:
$ touch my.file
$ ls my.file
$ echo $? #first echo
0
$ ls no.file
ls: no.file: No such file or directory
$ echo $? #second echo
1
$ echo $? #third echo
0
上例的:
ls my.file的 RV,可得到 0 的值,因此為 true。ls no.file的 RV,得到非 0 的值,因此為 false。echo $?的 RV,得到 0 值,因此為 true。請記?。?每一個 command 在結束時,都會返回return value,不管你跑什么命令... 然而,有一個命令卻是 “專門” 用來測試某一條而返回return value, 以供 true 或 false 的判斷, 它就是test命令。
若你用的是 bash, 請在 command line 下, 打man test,或者 man bash 來了解這個test的用法。 這是你可用作參考的最精準的文件了,要是聽別人說的,僅作參考就好...
下面,我只簡單作一些輔助說明,其余的一律以 man為準: 首先,test的表達式,我們稱為 expression,其命令格式有兩種:
test expression
或者
[ expression ]
Note:
請務必注意 [] 之間的空白鍵!
用哪一種格式無所謂,都是一樣的效果。 (我個人比較喜歡后者...)
其次,bash 的test目前支持的測試對象只有三種:
請初學者,一定要搞清楚這三者的差異, 因為test所使用的 expression 是不一樣的。
以 A=123 這個變量為例:
[ "$A" = 123 ] #是字符串測試,測試 $A 是不是 1、2、3 這三個字符。
[ "$A" -eq 123 ] #是整數測試,以測試 $A 是否等于 123。
[-e "$A" ] #文件測試,測試 123 這份文件是否存在。第三, 當 expression 測試為 “真” 時, test就返回 0(true) 的return value; 否則,返回非 0(false).
若在 expression 之前加一個!(感嘆號),則在 expression 為假時,return value 為 0, 否則, return value 為非 0 值。
同時,test也允許多重復合測試:
例如:
[ -d "$file" -a -x "$file" ]
表示當 $file 是一個目錄,且同時具有 x 權限時,test 才會為 true。
第四,在 command line 中使用test時,請別忘記命令行的 “重組” 特性, 也就是在碰到 meta 時,會先處理 meta,在重新組建命令行。 (這個概念在第 2 章和第 4 章進行了反復強調)
比方說,若test碰到變量或者命令替換時, 若不能滿足 expression 的格式時,將會得到語法錯誤的結果。
舉例來說好了:
關于[ string1 = string2 ]這個 test 格式, 在等號兩邊必須要有字符串,其中包括空串 (null 串, 可用 soft quote 或者 hard quote 取得)。
假如 $A 目前沒有定義,或被定義為空字符串的話, 那如下的用法將會失敗:
$ unset A
$ [ $A = abc ]
[: =: unary oprator expected
這是因為命令行碰到 $ 這個 meta 時,會替換 $A 的值, 然后,再重組命令行,那就變成了: [ = abc ], 如此一來,= 的左邊就沒有字符串存在了, 因此,造成 test 的語法錯誤。 但是,下面這個寫法則是成立的。
$ [ "$A" = abc ]
$ echo $?
1
這是因為命令行重組后的結果為: [ "" = abc ], 由于等號的左邊我們用 soft quote 得到一個空串, 而讓 test 的語法得以通過...
讀者諸君,請務必留意這些細節(jié)哦, 因為稍一不慎,將會導致test的結果變了個樣。 若您對test還不是很有經驗的話, 那在使用 test 時,不妨先采用如下這一個 "法則":
若在test中碰到變量替換,用 soft quote 是最保險的。
若你對 quoting 不熟的話,請重新溫習第四章的內容吧...^_^
okay, 關于更多的test的用法,老話一句:請看其 man page (man test) 吧!^_^
雖然洋洋灑灑讀了一大堆,或許你還在嘀咕... 那... 那個return value有啥用?
問得好: 告訴你:return value 的作用可大了, 若你想要你的 shell 變 "聰明" 的話,就全靠它了: 有了 return value, 我們可以讓 shell 根據不同的狀態(tài)做不同的事情...
這時候,才讓我來揭曉本章的答案吧~~~~^_^
&& 與 || 都是用來 "組建" 多個 command line 用的;
command1 && command2 # command2 只有在 command1 的 RV 為 0(true) 的條件下執(zhí)行。command1 || command2 # command2 只有在 command1 的 RV 為非 0(false) 的條件下執(zhí)行。以例子來說好了:
$ A=123
$ [ -n "$A" ] && echo "yes! it's true."
yes! it's true.
$ unset A
$ [ -n "$A" ] && echo "yes! it's true."
$ [ -n "$A" ] || echo "no, it's Not true."
no, it's Not true
Note:
[ -n string ]是測試 string 長度大于 0, 則為 true。
上例中,第一個&&命令之所以會執(zhí)行其右邊的echo命令, 是因為上一個test返回了 0 的 RV 值; 但第二個,就不會執(zhí)行,因為test返回了非 0 的結果... 同理,||右邊的echo會被執(zhí)行,卻正是因為左邊的test返回非 0 所引起的。
事實上,我們在同一個命令行中,可用多個&& 或 || 來組建呢。
$ A=123
$ [ -n "$A" ] && echo "yes! it's true." || echo "no, it's Not ture."
yes! it's true.
$ unset A
$ [ -n "$A" ] && echo "yes! it's true." || echo "no, it's Not ture."
no, it's Not true
怎樣,從這一刻開始,你是否覺得我們的 shell 是 “很聰明” 的呢? ^_^
好了,最后布置一道練習題給大家做做看: 下面的判斷是:當 $A 被賦值時,在看看其是否小于 100,否則輸出 too big!
$ A=123
$ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
$ too big!
若我取消 A,照理說,應該不會輸出文字啊,(因為第一個條件不成立)。
$ unset A
$ [ -n "$A" ] && [ "$A" -lt 100 ] || echo 'too big!'
$ too big!
為何上面的結果也可得到呢? 又如何解決呢?
Tips:
修改的方法有很多種, 其中一種方法可以利用第 7 章中介紹過 command group...
快告訴我答案,其余免談....
解決方法 1:sub-shell:
$ unset A
$ [ -n "$A" ] && ( [ "$A" -lt 100 ] || echo 'too big!' )
解決方法二:command group:
$ unset A
$ [ -n "$A" ] && { [ "$A" -lt 100 ] || echo 'too big!'}