bash中(),{},(()),[],[[]]的區別

前言:在bash中遇到各種括號,同時在進行字符數值比較判定時,總是不斷出現問題,於是通過參考《advanced bash-scripting guide》,同時在centos 6.7版本上進行測試,現況總結如下。如有紕漏,望指正。



一.()

一個命令組合,相當於一個命令組

[root@mghuee~chunlanyy testdir]# I=123;(I=xyz;echo $I;);echo $I
xyz
123



二.{}

同"{}",也爲一個命令組合,與"()"的區別就是前者在是當前shell中進行,而後者在裏面子shell中進行

[root@mghuee~chunlanyy testdir]# I=123;(echo $I;I=xyz;echo $I;);echo $I
123
xyz
123
[root@mghuee~chunlanyy testdir]# I=123;{ echo $I;I=xyz;echo $I; };echo $I
123
xyz
xyz

從例子中可以看得,"()"中的賦值只能影響到自身子shell,並不會賦值給父shell,而"{}"則只是在同一shell進行

另外需要注意的是,"{}"是一個keyword,所以在命令與兩邊的"{"需用空格隔離,同時使用";"表示命令結束。

[root@mghuee~chunlanyy testdir]# type {
{ is a shell keyword




三.[]

"[]"主要用作條件判斷,判斷對象包括文件類型和賦值比較

[root@mghuee~chunlanyy testdir]# type [
[ is a shell builtin

我們可以看到"["是一個內部命令,基本可認爲等同於test命令

[root@mghuee~chunlanyy testdir]# [ 4 -lt 3 ] && echo yes || echo no
no
[root@mghuee~chunlanyy testdir]#  test 4 -lt 3  && echo yes || echo no
no


常見的比較測試如下:

數字測試:-eq -ne -lt -le -gt -ge

文件測試:-r、-l、-w、-x、-f、-d、-s、-nt、-ot

字符串測試:=、!=、-n、-z、\>、\<

邏輯測試:-a、-o、!

數學運算:支持整數運算,但已被"((...))"取代


注意的幾點:

1.數字比較只能用-lt這樣的比較符,而不能使用"<"這樣的比較符,即便是加了轉義符的"\<"

[root@mghuee~chunlanyy testdir]# [ 1 > 2 ] && echo yes || echo no
yes

很顯然,"1>2"應該是錯誤的,但是顯示"yes",實際上此處">"並非算術比較中的大於號,而爲重定向輸出,通過ls命令即可查看出當前目錄下多出一個文件名爲2的文件

[root@mghuee~chunlanyy testdir]# ll -l
total 0
-rw-r--r--. 1 root root 0 Jun 17 20:53 2

有人也會試想通過轉義符進行數值比較

[root@mghuee~chunlanyy testdir]# [ 1 \> 2 ] && echo yes || echo no
no

通過此比較符合我們的預期,但是"\>"在此並非進行我們日常中理解的大小數值比較

[root@mghuee~chunlanyy testdir]# [ a \> 2 ] && echo yes || echo no
yes

此處比較是進行ASCII碼值大小比較,同時此處只能支持單字符的大小比較

[root@mghuee~chunlanyy testdir]# [ 5 \> 20 ] && echo yes || echo no
yes


2."[]"支持的邏輯運算符爲-a、-o、!,此處-a、-o相當於是test命令的一個參數,不能使用&&、||

[root@mghuee~chunlanyy testdir]# [ 1 -lt  2 && 1 -lt 3 ] && echo yes || echo no
-bash: [: missing `]'
no

&&和||是強邏輯運算,會對命令進行拆分,在上述舉例中已經拆分成"[ 1 -lt  2 " && "1 -lt 3 ]",故會顯示沒有配對的"["


在邏輯運算時,[ expre1 -a expre 2 ]與[[ expre1 && expre2 ]]並非完全一致,&&會進行邏輯短路操作,而-a並不會

[root@mghuee~chunlanyy testdir]# [ 1 -gt 3 -a 2 > test1.txt ] && echo yes || echo no
no
[root@mghuee~chunlanyy testdir]# ls
test1.txt

並未進行邏輯短路操作,執行所有判斷,即使"1 -gt 3"已經錯誤,依舊執行後續操作,雖然結果爲no,但是還會生成test1.txt文件

[root@mghuee~chunlanyy testdir]# [[ 1 -gt 3 && 2 > test2.txt ]] && echo yes || echo no
no
[root@mghuee~chunlanyy testdir]# ls
test1.txt

進行邏輯運算操作,在與命令中,"1 -gt 3"爲false即不作後續判斷,故無test2.txt的出現


3."[]"是命令,故在其中的變量引用或常量,需使用雙引號或者單引號括起來,因爲會出現單詞分割(Word-Splitting)現象

[root@mghuee~chunlanyy testdir]# I=" 29";[ -f $I ] && echo yes || echo no
no
[root@mghuee~chunlanyy testdir]# I=" 29";[ -f "$I" ] && echo yes || echo no
yes
[root@mghuee~chunlanyy testdir]# ll -a
total 8
drwxr-xr-x. 2 root root 4096 Jun 17 23:20 .
drwxrwxrwt. 6 root root 4096 Jun 17 20:53 ..
-rw-r--r--. 1 root root    0 Jun 17 23:17  29

在當前目錄中存在一個文件名爲" 29"的文件(29前面有空格),在[]中未對引用變量加入雙引號時,[]內部執行判斷爲-f "29",因爲當前目錄中不存在文件名的"29"的文件,顯示結果是No


四.(())

支持四則運算,等同於let功能

[root@mghuee~chunlanyy testdir]# let I=2+4;echo $I
6
[root@mghuee~chunlanyy testdir]# I=$((2+4));echo $I
6

五.[[]]

"[["也是一個keyword,用於比較判斷,基本支持"[]"中所有的判斷比較符。

[root@mghuee~chunlanyy testdir]# type [[
[[ is a shell keyword


"[["和"["的不同點:

1.邏輯運算符不一致,"[[]]"爲"&&"、"||","[]"爲"-a"、"-o"。"[[]]"支持邏輯短路,而"[]"不支持

2."[[]]"支持正則表達式的匹配。

3."[[]]"爲一個keyword,同括號與表達式中間必須要有空格進行隔離

4."[[]]"中使用比較符時不能轉義,同時不會出現Word-Splitting

[root@mghuee~chunlanyy testdir]# I=" 29";[[ -f $I ]] && echo yes || echo no
yes
[root@mghuee~chunlanyy testdir]# ll -a
total 8
drwxr-xr-x. 2 root root 4096 Jun 17 23:20 .
drwxrwxrwt. 6 root root 4096 Jun 17 20:53 ..
-rw-r--r--. 1 root root    0 Jun 17 23:17  29

與上述"[]"的結果進行比較,很顯然,在"[[]]"中並不會出現Word-Splitting

[root@mghuee~chunlanyy testdir]# [[ a > 1 ]] && echo yes || echo no
yes
[root@mghuee~chunlanyy testdir]# [[ a \> 1 ]] && echo yes || echo no
-bash: conditional binary operator expected
-bash: syntax error near `\>'

可以看出,使用轉義後出現error

5.[[]]中"=="與"=~"的使用

引用《advanced bash-scripting guide》對兩者的解釋

== String comparison operator   <==字符串比較

=~ Regular Expression match operator  <==正則表達式匹配


但是在此也並非代表"=="在"[[]]"中不能實現正則表達式模式的匹配,也能實現部分的匹配

[root@mghuee~chunlanyy tmp]# [[ abc == a*b***c ]] && echo yes || echo no
yes

但只能實現字符之間的匹配

[root@mghuee~chunlanyy tmp]# [[ `cat /etc/passwd` == ^root ]] && echo yes || echo no
no
[root@mghuee~chunlanyy tmp]# [[ `cat /etc/passwd` =~ ^root ]] && echo yes || echo no
yes

而"=~"則能完整的按正則表達式去匹配


注意:在正則表達式模式匹配中,右邊的匹配模式不能使用雙引號,在bash 3.2版本之後已經明確說明在使用正則表達式時所匹配的模式不能加上雙引號

[root@mghuee~chunlanyy tmp]# [[ `cat /tmp/123` =~ "^root" ]] && echo yes || echo no
yes
[root@mghuee~chunlanyy tmp]# cat 123
"^root"
[root@mghuee~chunlanyy tmp]# [[ `cat /tmp/123` =~ ^root ]] && echo yes || echo no
no
[root@mghuee~chunlanyy tmp]# cat 123
"^root"

因爲在"[[]]"不會出現Word-Splitting,加入後反而讓上匹配模式變成了“"^root"”



小結:

1.進行算術運算時使用"let命令",或者"$(())""
2.進行文件存在或者字符是否爲空時使用"[]"
3.邏輯運算符"&&"、"||"要在"[[]]"中使用,"-a"、"-o"在"[]"中使用
4.在"[[]]"中使用正則表達式進行匹配的時候所匹配模式不能使用雙引號
5.數值大小比較時在"[]"中進行比較,要使用"-lt"、"-gt"這樣的比較符,不能使用"<"、">"
6."[[]]"與"[]"兩邊最好都保持空格,"[[]]"是兩邊一定要有空格進行隔離
7.以上均爲習慣使用方式,並非說明其它組合模式一定不可使用,但可避免出現一些讓人費解的錯誤



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章