一文讀懂 Shell 中各種括號的作用

一、小括號,圓括號()

1、單小括號 ()

①命令組。括號中的命令將會新開一個子 shell 順序執行,所以括號中的變量不能夠被腳本餘下的部分使用。括號中多個命令之間用分號隔開,最後一個命令可以沒有分號,各命令和括號之間不必有空格。

②命令替換。等同於 cmd,shell 掃描一遍命令行,發現了 $(cmd) 結構,便將 $(cmd) 中的 cmd 執行一次,得到其標準輸出,再將此輸出放到原來命令。有些 shell 不支持,如 tcsh。

③用於初始化數組。如:array=(a b c d)

2、雙小括號 (())

①整數擴展。這種擴展計算是整數型的計算,不支持浮點型。((exp)) 結構擴展並計算一個算術表達式的值,如果表達式的結果爲 0,那麼返回的退出狀態碼爲 1,或者 是 "假",而一個非零值的表達式所返回的退出狀態碼將爲 0,或者是 "true"。若是邏輯判斷,表達式 exp 爲真則爲 1, 假則爲 0。

②只要括號中的運算符、表達式符合 C 語言運算規則,都可用在 $((exp))中,甚至是三目運算符。作不同進位 (如二進制、八進制、十六進制) 運算時,輸出結果全都自動轉化成了十進制。如:echo $((16#5f)) 結果爲 95 (16 進位轉十進制)

③單純用 (()) 也可重定義變量值,比如 a=5; ((a++)) 可將 $a 重定義爲 6

④常用於算術運算比較,雙括號中的變量可以不使用 $ 符號前綴。括號內支持多個表達式用逗號分開。只要括號中的表達式符合 C 語言運算規則, 比如可以直接使用 for((i=0;i<5;i++)), 如果不使用雙括號, 則爲 for i in seq 0 4 或者 for i in {0..4}。再如可以直接使用 if (($i<5)), 如果不使用雙括號, 則爲 if [ $i -lt 5 ]。

二、中括號,方括號 []

1、單中括號 []

①bash 的內部命令,[和 test 是等同的。如果我們不用絕對路徑指明,通常我們用的都是 bash 自帶的命令。if/test 結構中的左中括號是調用 test 的命令標識,右中括號是關閉條件判斷的。這個命令把它的參數作爲比較表達式或者作爲文件測試,並且根據比較的結果來返回一個退出狀態碼。if/test 結構中並不是必須右中括號,但是新版的 Bash 中要求必須這樣。

②Test 和 [] 中可用的比較運算符只有 == 和!=,兩者都是用於字符串比較的,不可用於整數比較,整數比較只能使用 - eq,-gt 這種形式。無論是字符串比較還是整數比較都不支持大於號小於號。如果實在想用,對於字符串比較可以使用轉義形式,如果比較 "ab" 和 "bc":[ ab < bc],結果爲真,也就是返回狀態爲 0。[ ]中的邏輯與和邏輯或使用 - a 和 - o 表示。

③字符範圍。用作正則表達式的一部分,描述一個匹配的字符範圍。作爲 test 用途的中括號內不能使用正則。

④在一個 array 結構的上下文中,中括號用來引用數組中每個元素的編號。

2、雙中括號 [[]]

①[[是 bash 程序語言的關鍵字。並不是一個命令,[[]] 結構比 [ ] 結構更加通用。在 [[和]] 之間所有的字符都不會發生文件名擴展或者單詞分割,但是會發生參數擴展和命令替換。

②支持字符串的模式匹配,使用 =~ 操作符時甚至支持 shell 的正則表達式。字符串比較時可以把右邊的作爲一個模式,而不僅僅是一個字符串,比如 [[hello == hell?]],結果爲真。[[ ]] 中匹配字符串或通配符,不需要引號。

③使用 [[...]] 條件判斷結構,而不是 [ ... ],能夠防止腳本中的許多邏輯錯誤。比如,&&、||、<和> 操作符能夠正常存在於[[ ]] 條件判斷結構中,但是如果出現在 [ ] 結構中的話,會報錯。比如可以直接使用 if [[ $a != 1 && $a != 2 ]], 如果不適用雙括號, 則爲 if [ $a -ne 1] && [ $a != 2 ]或者 if [ $a -ne 1 -a $a != 2 ]。

④bash 把雙中括號中的表達式看作一個單獨的元素,並返回一個退出狀態碼。

例子:

if ($i<5) 
if [ $i -lt 5 ] 
if [ $a -ne 1 -a $a != 2 ] 
if [ $a -ne 1] && [ $a != 2 ] 
if [[ $a != 1 && $a != 2 ]] 
for i in $(seq 0 4);do echo $i;done
for i in `seq 0 4`;do echo $i;done
for ((i=0;i<5;i++));do echo $i;done
for i in {0..4};do echo $i;done

三、大括號、花括號 {}

1、常規用法

①大括號拓展。(通配 (globbing)) 將對大括號中的文件名做擴展。在大括號中,不允許有空白,除非這個空白被引用或轉義。第一種:對大括號中的以逗號分割的文件列表進行拓展。如 touch {a,b}.txt 結果爲 a.txt b.txt。第二種:對大括號中以點點(..)分割的順序文件列表起拓展作用,如:touch {a..d}.txt 結果爲 a.txt b.txt c.txt d.txt

# ls {ex1,ex2}.sh 
ex1.sh ex2.sh 
# ls {ex{1..3},ex4}.sh 
ex1.sh ex2.sh ex3.sh ex4.sh 
# ls {ex[1-3],ex4}.sh 
ex1.sh ex2.sh ex3.sh ex4.sh

②代碼塊,又被稱爲內部組,這個結構事實上創建了一個匿名函數 。與小括號中的命令不同,大括號內的命令不會新開一個子 shell 運行,即腳本餘下部分仍可使用括號內變量。括號內的命令間用分號隔開,最後一個也必須有分號。{} 的第一個命令和左括號之間必須要有一個空格。

2、幾種特殊的替換結構

${var:-string},${var:+string},${var:=string},${var:?string}

①${var:-string} 和 ${var:=string}: 若變量 var 爲空,則用在命令行中用 string 來替換 ${var:-string},否則變量 var 不爲空時,則用變量 var 的值來替換 ${var:-string};對於 ${var:=string} 的替換規則和 ${var:-string} 是一樣的,所不同之處是 ${var:=string} 若 var 爲空時,用 string 替換 ${var:=string} 的同時,把 string 賦給變量 var: ${var:=string} 很常用的一種用法是,判斷某個變量是否賦值,沒有的話則給它賦上一個默認值。

② ${var:+string} 的替換規則和上面的相反,即只有當 var 不是空的時候才替換成 string,若 var 爲空時則不替換或者說是替換成變量 var 的值,即空值。(因爲變量 var 此時爲空,所以這兩種說法是等價的)

③${var:?string} 替換規則爲:若變量 var 不爲空,則用變量 var 的值來替換 ${var:?string};若變量 var 爲空,則把 string 輸出到標準錯誤中,並從腳本中退出。我們可利用此特性來檢查是否設置了變量的值。

補充擴展:在上面這五種替換結構中 string 不一定是常值的,可用另外一個變量的值或是一種命令的輸出。

3、四種模式匹配替換結構

模式匹配記憶方法:

是去掉左邊 (在鍵盤上 #在 $ 之左邊)

% 是去掉右邊 (在鍵盤上 % 在 $ 之右邊)

#和 % 中的單一符號是最小匹配,兩個相同符號是最大匹配。

${var%pattern},${var%%pattern},${var#pattern},${var##pattern}

第一種模式:${variable%pattern},這種模式時,shell 在 variable 中查找,看它是否一給的模式 pattern 結尾,如果是,就從命令行把 variable 中的內容去掉右邊最短的匹配模式

第二種模式: ${variable%%pattern},這種模式時,shell 在 variable 中查找,看它是否一給的模式 pattern 結尾,如果是,就從命令行把 variable 中的內容去掉右邊最長的匹配模式

第三種模式:${variable#pattern} 這種模式時,shell 在 variable 中查找,看它是否一給的模式 pattern 開始,如果是,就從命令行把 variable 中的內容去掉左邊最短的匹配模式

第四種模式: ${variable##pattern} 這種模式時,shell 在 variable 中查找,看它是否一給的模式 pattern 結尾,如果是,就從命令行把 variable 中的內容去掉右邊最長的匹配模式

這四種模式中都不會改變 variable 的值,其中,只有在 pattern 中使用了 * 匹配符號時,% 和 %%,# 和 ## 纔有區別。結構中的 pattern 支持通配符,* 表示零個或多個任意字符,? 表示僅與一個任意字符匹配,[...] 表示匹配中括號裏面的字符,[!...] 表示不匹配中括號裏面的字符。

# var=testcase 
# echo $var 
testcase 
# echo ${var%s*e} 
testca 
# echo $var 
testcase 
# echo ${var%%s*e} 
te 
# echo ${var#?e} 
stcase 
# echo ${var##?e} 
stcase 
# echo ${var##*e}
# echo ${var##*s} # echo ${var##test} 
case

4、字符串提取和替換

${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern}

第一種模式:${var:num},這種模式時,shell 在 var 中提取第 num 個字符到末尾的所有字符。若 num 爲正數,從左邊 0 處開始;若 num 爲負數,從右邊開始提取字串,但必須使用在冒號後面加空格或一個數字或整個 num 加上括號,如 ${var: -2}、${var:1-3} 或 ${var:(-2)}。

第二種模式:${var:num1:num2},num1 是位置,num2 是長度。表示從 $var 字符串的第 $num1 個位置開始提取長度爲 $num2 的子串。不能爲負數。

第三種模式:${var/pattern/pattern} 表示將 var 字符串的第一個匹配的 pattern 替換爲另一個 pattern。

第四種模式:${var//pattern/pattern} 表示將 var 字符串中的所有能匹配的 pattern 替換爲另一個 pattern。

[root@centos ~]# var=/home/centos 
[root@centos ~]# echo $var 
/home/centos
[root@centos ~]# echo ${var:5} 
/centos
[root@centos ~]# echo ${var: -6} 
centos 
[root@centos ~]# echo ${var:(-6)} 
centos 
[root@centos ~]# echo ${var:1:4} 
home 
[root@centos ~]# echo ${var/o/h} 
/hhme/centos
[root@centos ~]# echo ${var//o/h} 
/hhme/cenths

四、符號 $ 後的括號

(1)${a} 變量 a 的值, 在不引起歧義的情況下可以省略大括號。

(2)$(cmd) 命令替換,和 cmd 效果相同,結果爲 shell 命令 cmd 的輸,過某些 Shell 版本不支持 $() 形式的命令替換, 如 tcsh。

(3)$((expression)) 和 exprexpression 效果相同, 計算數學表達式 exp 的數值, 其中 exp 只要符合 C 語言的運算規則即可, 甚至三目運算符和邏輯表達式都可以計算。

五、使用

多條命令執行

(1)單小括號,(cmd1;cmd2;cmd3) 新開一個子 shell 順序執行命令 cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後可以沒有分號。

(2)單大括號,{cmd1;cmd2;cmd3;} 在當前 shell 順序執行命令 cmd1,cmd2,cmd3, 各命令之間用分號隔開, 最後一個命令後必須有分號, 第一條命令和左括號之間必須用空格隔開。

對 {} 和()而言, 括號中的重定向符隻影響該條命令, 而括號外的重定向符影響到括號中的所有命令。

作者:烏托邦 2 號 

來源:blog.csdn.net/taiyang1987912/article/details/39551385

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Ttceo5DKTXHRp-FwZnxy7w