天天看點

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把雙中括号中的表達式看作一個單獨的元素,并傳回一個退出狀态碼。

例子:

1

2

3

4

5

6

7

8

9

<code>if</code> <code>($i&lt;5)</code>

<code>if</code> <code>[ $i -lt 5 ]</code>

<code>if</code> <code>[ $a -</code><code>ne</code> <code>1 -a $a != 2 ]</code>

<code>if</code> <code>[ $a -</code><code>ne</code> <code>1] &amp;&amp; [ $a != 2 ]</code>

<code>if</code> <code>[[ $a != 1 &amp;&amp; $a != 2 ]]</code>

<code>for</code> <code>i</code><code>in</code> <code>$(</code><code>seq</code> <code>0 4);</code><code>do</code> <code>echo</code> <code>$i;</code><code>done</code>

<code>for</code> <code>i</code><code>in</code> <code>`</code><code>seq</code> <code>0 4`;</code><code>do</code> <code>echo</code> <code>$i;</code><code>done</code>

<code>for</code> <code>((i=0;i&lt;5;i++));</code><code>do</code> <code>echo</code> <code>$i;</code><code>done</code>

<code>for</code> <code>i</code><code>in</code> <code>{0..4};</code><code>do</code> <code>echo</code> <code>$i;</code><code>done</code>

三、大括号、花括号 {}

1、正常用法

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

<code># ls {ex1,ex2}.sh</code>

<code>ex1.sh ex2.sh</code>

<code># ls {ex{1..3},ex4}.sh</code>

<code>ex1.sh ex2.sh ex3.sh ex4.sh</code>

<code># ls {ex[1-3],ex4}.sh</code>

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

2、幾種特殊的替換結構

<code>${var:-string},${var:+string},${var:=string},${var:?string}</code>

  ①<code>${var:-string}和${var:=string}</code>:若變量var為空,則用在指令行中用string來替換<code>${var:-string}</code>,否則變量var不為空時,則用變量var的值來替換<code>${var:-string}</code>;對于<code>${var:=string}</code>的替換規則和<code>${var:-string}</code>是一樣的,所不同之處是<code>${var:=string}</code>若var為空時,用string替換<code>${var:=string}</code>的同時,把string賦給變量var: <code>${var:=string}</code>很常用的一種用法是,判斷某個變量是否指派,沒有的話則給它賦上一個預設值。

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

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

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