📄 1894.html
字号:
代码:
$ a=5; b=7; c=2
$ echo $(( a+b*c ))
19
$ echo $(( (a+b)/c ))
6
$ echo $(( (a*b)%c))
1
在 $(( )) 中的變量,可用 $ 符號來替換,也可以不用,如:
$(( $a + $b * $c)) 也可得到 19 的結果
此外,$(( )) 還可作不同進位(如二進位、八進位、十六進位)作運算呢,只是,輸出結果皆為十進位而已:
echo $((16#2a)) 結果為 42 (16進位轉十進位)
以一個實用的例子來看看吧:
假如當前的 umask 是 022 ,那麼新建文件的權限即為:
代码:
$ umask 022
$ echo "obase=8;$(( 8#666 & (8#777 ^ 8#$(umask)) ))" | bc
644
事實上,單純用 (( )) 也可重定義變量值,或作 testing:
a=5; ((a++)) 可將 $a 重定義為 6
a=5; ((a--)) 則為 a=4
a=5; b=7; ((a < b)) 會得到 0 (true) 的返回值。
常見的用於 (( )) 的測試符號有如下這些:
<:小於
>:大於
<=:小於或等於
>=:大於或等於
==:等於
!=:不等於
不過,使用 (( )) 作整數測試時,請不要跟 [ ] 的整數測試搞混亂了。(更多的測試我將於第十章為大家介紹)
怎樣?好玩吧.. ^_^ okay,這次暫時說這麼多...
上面的介紹,並沒有詳列每一種可用的狀態,更多的,就請讀者參考手冊文件囉...
9) $@ 與 $* 差在哪?
要說 $@ 與 $* 之前,需得先從 shell script 的 positional parameter 談起...
我們都已經知道變量(variable)是如何定義及替換的,這個不用再多講了。
但是,我們還需要知道有些變量是 shell 內定的,且其名稱是我們不能隨意修改的,
其中就有 positional parameter 在內。
在 shell script 中,我們可用 $0, $1, $2, $3 ... 這樣的變量分別提取命令行中的如下部份:
代码:
script_name parameter1 parameter2 parameter3 ...
我們很容易就能猜出 $0 就是代表 shell script 名稱(路逕)本身,而 $1 就是其後的第一個參數,如此類推....
須得留意的是 IFS 的作用,也就是,若 IFS 被 quoting 處理後,那麼 positional parameter 也會改變。
如下例:
代码:
my.sh p1 "p2 p3" p4
由於在 p2 與 p3 之間的空白鍵被 soft quote 所關閉了,因此 my.sh 中的 $2 是 "p2 p3" 而 $3 則是 p4 ...
還記得前兩章我們提到 fucntion 時,我不是說過它是 script 中的 script 嗎? ^_^
是的,function 一樣可以讀取自己的(有別於 script 的) postitional parameter ,惟一例外的是 $0 而已。
舉例而言:假設 my.sh 裡有一個 fucntion 叫 my_fun , 若在 script 中跑 my_fun fp1 fp2 fp3 ,
那麼,function 內的 $0 是 my.sh ,而 $1 則是 fp1 而非 p1 了...
不如寫個簡單的 my.sh script 看看吧:
代码:
#!/bin/bash
my_fun() {
echo '$0 inside function is '$0
echo '$1 inside function is '$1
echo '$2 inside function is '$2
}
echo '$0 outside function is '$0
echo '$1 outside function is '$1
echo '$2 outside function is '$2
my_fun fp1 "fp2 fp3"
然後在 command line 中跑一下 script 就知道了:
代码:
chmod +x my.sh
./my.sh p1 "p2 p3"
$0 outside function is ./my.sh
$1 outside function is p1
$2 outside function is p2 p3
$0 inside function is ./my.sh
$1 inside function is fp1
$2 inside function is fp2 fp3
然而,在使用 positional parameter 的時候,我們要注意一些陷阱哦:
* $10 不是替換第 10 個參數,而是替換第一個參數($1)然後再補一個 0 於其後﹗
也就是,my.sh one two three four five six seven eigth nine ten 這樣的 command line ,
my.sh 裡的 $10 不是 ten 而是 one0 哦... 小心小心﹗
要抓到 ten 的話,有兩種方法:
方法一是使用我們上一章介紹的 ${ } ,也就是用 ${10} 即可。
方法二,就是 shift 了。
用通俗的說法來說,所謂的 shift 就是取消 positional parameter 中最左邊的參數( $0 不受影響)。
其預設值為 1 ,也就是 shift 或 shift 1 都是取消 $1 ,而原本的 $2 則變成 $1、$3 變成 $2 ...
若 shift 3 則是取消前面三個參數,也就是原本的 $4 將變成 $1 ...
那,親愛的讀者,你說要 shift 掉多少個參數,才可用 $1 取得 ${10} 呢? ^_^
okay,當我們對 positional parameter 有了基本概念之後,那再讓我們看看其他相關變量吧。
首先是 $# :它可抓出 positional parameter 的數量。
以前面的 my.sh p1 "p2 p3" 為例:
由於 p2 與 p3 之間的 IFS 是在 soft quote 中,因此 $# 可得到 2 的值。
但如果 p2 與 p3 沒有置於 quoting 中話,那 $# 就可得到 3 的值了。
同樣的道理在 function 中也是一樣的...
因此,我們常在 shell script 裡用如下方法測試 script 是否有讀進參數:
代码:
[ $# = 0 ]
假如為 0 ,那就表示 script 沒有參數,否則就是有帶參數...
接下來就是 $@ 與 $* :
精確來講,兩者只有在 soft quote 中才有差異,否則,都表示"全部參數"( $0 除外)。
舉例來說好了:
若在 command line 上跑 my.sh p1 "p2 p3" p4 的話,
不管是 $@ 還是 $* ,都可得到 p1 p2 p3 p4 就是了。
但是,如果置於 soft quote 中的話:
"$@" 則可得到 "p1" "p2 p3" "p4" 這三個不同的詞段(word)﹔
"$*" 則可得到 "p1 p2 p3 p4" 這一整串單一的詞段。
我們可修改一下前面的 my.sh ,使之內容如下:
代码:
#!/bin/bash
my_fun() {
echo "$#"
}
echo 'the number of parameter in "$@" is '$(my_fun "$@")
echo 'the number of parameter in "$*" is '$(my_fun "$*")
然後再執行 ./my.sh p1 "p2 p3" p4 就知道 $@ 與 $* 差在哪了 ... ^_^
10) && 與 || 差在哪?
好不容易,進入兩位數的章節了... 一路走來,很辛苦吧?也很快樂吧? ^_^
在解答本章題目之前,先讓我們了解一個概念:return value ﹗
我們在 shell 下跑的每一個 command 或 function ,在結束的時候都會傳回父行程一個值,稱為 return value 。
在 shell command line 中可用 $? 這個變量得到最"新"的一個 return value ,也就是剛結束的那個行程傳回的值。
Return Value(RV) 的取值為 0-255 之間,由程式(或 script)的作者自行定議:
* 若在 script 裡,用 exit RV 來指定其值,若沒指定,在結束時以最後一道命令之 RV 為值。
* 若在 function 裡,則用 return RV 來代替 exit RV 即可。
Return Value 的作用,是用來判斷行程的退出狀態(exit status),只有兩種:
* 0 的話為"真"( true )
* 非 0 的話為"假"( false )
舉個例子來說明好了:
假設當前目錄內有一份 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
上例的第一個 echo 是關於 ls my.file 的 RV ,可得到 0 的值,因此為 true ﹔
第二個 echo 是關於 ls no.file 的 RV ,則得到非 0 的值,因此為 false ﹔
第三個 echo 是關於第二個 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
or:
[ expression ]
(請務必注意 [ ] 之間的空白鍵﹗)
用哪一種格式沒所謂,都是一樣的效果。(我個人比較喜歡後者...)
其次,bash 的 test 目前支援的測試對像只有三種:
* string:字串,也就是純文字。
* integer:整數( 0 或正整數,不含負數或小數點)。
* file:文件。
請初學者一定要搞清楚這三者的差異,因為 test 所用的 expression 是不一樣的。
以 A=123 這個變量為例:
* [ "$A" = 123 ]:是字串的測試,以測試 $A 是否為 1、2、3 這三個連續的"文字"。
* [ "$A" -eq 123 ]:是整數的測試,以測試 $A 是否等於"一百二十三"。
* [ -e "$A" ]:是關於文件的測試,以測試 123 這份"文件"是否存在。
第三,當 expression 測試為"真"時,test 就送回 0 (true) 的 return value ,否則送出非 0 (false)。
若在 expression 之前加上一個 " ! "(感嘆號),則是當 expression 為"假時" 才送出 0 ,否則送出非 0 。
同時,test 也允許多重的覆合測試:
* expression1 -a expression2 :當兩個 exrepssion 都為 true ,才送出 0 ,否則送出非 0 。
* expression1 -o expression2 :只需其中一個 exrepssion 為 true ,就送出 0 ,只有兩者都為 false 才送出非 0 。
例如:
代码:
[ -d "$file" -a -x "$file" ]
是表示當 $file 是一個目錄、且同時具有 x 權限時,test 才會為 true 。
第四,在 command line 中使用 test 時,請別忘記命令行的"重組"特性,
也就是在碰到 meta 時會先處理 meta 再重新組建命令行。(這個特性我在第二及第四章都曾反覆強調過)
比方說,若 test 碰到變量或命令替換時,若不能滿足 expression 格式時,將會得到語法錯誤的結果。
舉例來說好了:
關於 [ string1 = string2 ] 這個 test 格式,
在 = 號兩邊必須要有字串,其中包括空(null)字串(可用 soft quote 或 hard quote 取得)。
假如 $A 目前沒有定義,或被定議為空字串的話,那如下的寫法將會失敗:
代码:
$ unset A
$ [ $A = abc ]
[: =: unary operator expected
這是因為命令行碰到 $ 這個 meta 時,會替換 $A 的值,然後再重組命令行,那就變成了:
[ = abc ]
如此一來 = 號左邊就沒有字串存在了,因此造成 test 的語法錯誤﹗
但是,下面這個寫法則是成立的:
代码:
$ [ "$A" = abc ]
$ echo $?
1
這是因為在命令行重組後的結果為:
[ "" = abc ]
由於 = 左邊我們用 soft quote 得到一個空字串,而讓 test 語法得以通過...
讀者諸君請務必留意這些細節哦,因為稍一不慎,將會導至 test 的結果變了個樣﹗
若您對 test 還不是很有經驗的話,那在使用 test 時不妨先採用如下這一個"法則":
* 假如在 test 中碰到變量替換,用 soft quote 是最保險的﹗
若你對 quoting 不熟的話,請重新溫習第四章的內容吧... ^_^
okay,關於更多的 test 用法,老話一句:請看 man page 吧﹗ ^_^
雖然洋洋灑灑講了一大堆,或許你還在嘀咕.... 那... 那個 return value 有啥用啊?﹗
問得好﹗
告訴你:return value 的作用可大了﹗若你想讓你的 shell 變"聰明"的話,就全靠它了:
* 有了 return value,我們可以讓 shell 跟據不同的狀態做不同的時情...
這時候,才讓我來揭曉本章的答案吧~~~ ^_^
&& 與 || 都是用來"組建"多個 command line 用的:
* command1 && command2 :其意思是 command2 只有在 RV 為 0 (true) 的條件下執行。
* command1 || command2 :其意思是 command2 只有在 RV 為非 0 (false) 的條件下執行。
來,以例子來說好了:
代码:
$ A=123
$ [ -n "$A" ] && echo "yes! it's ture."
yes! it's ture.
$ unset A
$ [ -n "$A" ] && echo "yes! it's ture."
$ [ -n "$A" ] || echo "no, it's NOT ture."
no, it's NOT ture.
(註:[ -n string ] 是測試 string 長度大於 0 則為 true 。)
上例的第一個 && 命令行之所以會執行其右邊的 echo 命令,是因為上一個 test 送回了 0 的 RV 值﹔
但第二次就不會執行,因為為 test 送回非 0 的結果...
同理,|| 右邊的 echo 會被執行,卻正是因為左邊的 test 送回非
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -