Bash 中 [[ ]] AND [ ] 或 (( )) AND ( ) 之間的區別

Bash 中 [[ ]] AND [ ] 或 (( )) AND ( ) 之間的區別

[[ condition ]]使用and[ condition ](( condition ))and有什麼差別( condition )?在什麼場景下我們需要使用其中任何一個?

  • (( 10 > 9 ))有效但(( 10 -gt 9 ))無效
  • [[ 10 -gt 9 ]]有效但[[ 10 > 9 ]]無效

答案1

((...))是外殼的算術構造。手冊中記錄了您可以使用的運算符:6.5 殼演算法

(...)是一個分組在子 shell 中執行所包含指令的構造:3.2.4.3 分組命令

[...]是「遺留」條件構造。文件位於6.4 Bash 條件表達式

[[...]]做所有該[...]做的事。不同之處在於,不會對內部變數執行分詞和全域擴展,[[...]]因此引用變數並不那麼重要。另外,[[還可以做模式匹配==操作員和正規表示式匹配=~操作員。

原因[[ 10 > 9 ]]給你意想不到的結果是>裡面的操作符[[...]]是for字串比較且字串“10”“小於”字串“9”。

答案2

關於((…))(…)

如中所述這個另一個答案,((…))是 shell 的算術結構(a巴什主義)並(…)在子 shell 中執行命令。它們彼此之間以及與[ … ]或 都非常不同[[ … ]]

另一方面,在簡單情況下[ … ][[ … ]]非常相似;他們可能會感到困惑。這個答案的其餘部分集中在[ … ][[ … ]]


正式說明

我的目標是:

  • 詳細說明[ … ]和之間的區別和相似之處[[ … ]];
  • [ … ]提供vs主題的規範答案,因此可以透過「不是」[[ … ]]回答的問題可以連結到此處;[[[
  • 提供足夠詳盡的答案,因此用戶不再試圖發布只關注單一差異的答案。

什麼是[

  1. [執行測試。

    的目的[是測試某些內容(例如,是否存在某個文件),如果測試成功則返回退出狀態零,否則返回非零。

  2. [是一個命令。

    [是一個命令名稱,例如catecho[(如echo) 是 Bash 中的內建命令,但這僅意味著它可以在不產生額外進程的情況下運行,它的行為仍然類似於命令。[您的系統中可能有一個獨立的可執行檔(例如/bin/[);試著type -a [使用 Bash 來找出答案。

  3. [後面需要一個空格。

    作為命令,[需要參數。與任何其他命令一樣,參數必須與另一個參數以及命令名稱分開。[foo是一個不同的命令名稱,它不等於[ foo(類似且更明顯的echoHello world是不是echo Hello world)。您當然需要在 後面有一個空格(或製表符)[

  4. [需要].

    [require]作為最後一個參數,否則它將無法運作。這只是為了讓其[ … ]作為一個塊脫穎而出,就好像它是某種特殊的語法一樣;但這不是特殊的語法。要]作為最後一個參數傳遞,您需要在其前面有一個空格(或製表符)。為了比較: [ … bar]is中的最後一個參數bar]is not ],所以[ … bar]不是有效的指令。

  5. [(幾乎)就像test.

    [ … ]相當於test ….換句話說,您可以透過刪除並更改命令名稱來將任何[命令轉換為命令。並且您可以透過更改命令名稱並添加.test]test[]

  6. [並不特別。

    最好記住[它並不特殊,它只是命令的一個有點奇特的名稱。如果您承認這一點,那麼您就不會對此感到驚訝全部shell 的解析與處理如果命令是 ,也會發生運行命令(testecho等) 。尤其:ls[

    • [不知道您是否引用了它的任何參數,它會在 shell 刪除引號後取得參數。

    • 未加引號且未轉義&&||介於[and之間的]內容不被解釋為 的參數[。換句話說,[ … || … ]被解釋為[ …(無效,因為沒有])和… ](一個單獨的命令,無論是什麼)與 邏輯連接||,完全相同command1 || command2

  7. [由 POSIX 指定。

    有的是POSIX 規範[/test。您可以撥打[手提電話。筆記:

    • 一些主要是擴展,一些被標記為過時。例如,我們的無效程式碼 ( [ … || … ]) 可以修復為[ … -o … ],但由於-o已過時,更好的修復方法是[ … ] || [ … ]
    • 實現可能支持更多初選。[Bash 中的內建函數可以做到這一點(請參閱 參考資料)help test;您的作業系統中的二進位檔案(如 )可能會(請參閱[)。/bin/[man test

什麼是[[?與有何[[不同[

注意:
- 問題已標記,現在我們正在談論[[ 在重擊中
- 本節編號的段落與上一節編號的段落相對應。

  1. (相似)[[執行測試。

    的目的[[是測試某些內容(例如,是否存在某個文件),如果測試成功則返回退出狀態零,否則返回非零。[[可以測試任何[可以的東西,甚至更多。

  2. (不同之處)[[是一個關鍵字。

    [[一個 shell 關鍵字(type [[在 Bash 中呼叫以確認這一點)。與builtin一樣[,該[[關鍵字屬於Bash;但它才不是表現得像一個命令。

  3. (相似)[[後面需要一個空格。

    (或選項卡)。

  4. (相似)[[需要]].

    [[需要]]稍後在程式碼中添加,但這不僅僅是為了使[[ … ]]程式碼區塊脫穎而出。這是一種特殊的語法(有一個區別,我們會討論它)。之前需要一個空格(或製表符)]]

  5. (不同之處)不存在與 等效的普通命令[[

    沒有其他命令/關鍵字/任何東西可以以可以替換的[[方式替換。test[

  6. (不同之處)[[ 特別的。

    [[改變 shell 解析和解釋程式碼的方式,直到匹配]]. shell 在運作之前執行的正常解析和處理[or test(或echols)不適用於 inside [[ … ]]。尤其:

    • [[ 請注意您是否引用了其中的任何“論點”。雙引號變數不是必需的(通常情況下這是),但在某些情況下,雙引號字串(或變數)會產生影響(請參閱這個答案=其中提到「 or==!=or的右側=~」)。

    • &&||之間[[]]屬於該[[ … ]]構造。[[ … || … ]]可以是一段有效的程式碼,實際上相當於[[ … ]] || [[ … ]].

  7. (不同之處)[[POSIX 沒有指定。

    [[便於攜帶。[[在 Bash 中工作,在 pure 中不起作用sh。其他 shell 可能支援[[(例如 Zsh),但它們可能與Bash[[不同。[[

    [[未設計為符合[/的規範test。在許多情況下,替換[with[[]with]]將為您提供[[ … ]]與原始[ … ]片段等效的片段;但不總是,有時內部需要調整。所以不要盲目[改變[[。盲目改成[[風險[更大,因為有些測試[[可以做,有些測試[不能做。


其他注意事項:

  1. Nor[都不[[是語法的一部分if … then …。請記住,if僅測試某些程式碼的退出狀態。if true; then …有效、if sleep 5; then …有效、類似if [ … ]; then …if [[ … ]]; then …有效(如果[ … ][[ … ]]部分本身是有效片段)。

    由於((…))or(…)也回傳一些退出狀態(這取決於內部內容),因此if也可以在之後使用。

  2. 就我個人而言,我更喜歡使用任何可以輕鬆完成的[測試,在真正必要時才使用。這樣我就不會習慣非可移植性,而且我知道我可以在不像 Bash 那樣豐富的 shell 中做什麼。[[[[[

  3. 作業系統中的可執行檔[不一定嚴格等同於[Bash 中的內建檔案。如果[由 Bash 調用,那麼內建函數將完成這項工作。如果[被其他東西調用,那麼可執行檔將完成這項工作。例如find … -exec [ … ] …使用可執行檔。沒有標準的[[可執行檔(至少在我知道的系統中),所以find … -exec [[ … ]] …永遠不會工作。如果有一個[[可執行文件,那麼它的行為必須像命令一樣,它無法模仿關鍵字。

答案3

[ ] 與 [[ ]] 之間存在巨大差異:

a=0;
if [ $a = 1 -a $(grep ERR 1.log|wc -l) -ne 0 ];then
      echo "error";
fi 

使用 [ ] 時,and 運算子 -a 不支援短路評估。在上面的程式碼中,即使第一個條件回傳 false,第二個條件仍然會被評估。如果檔案1.log不存在,它會抱怨「沒有這樣的檔案或目錄」。

但對於 [[ ]]:

a=0
if [[ $a = 1 && $(grep ERR 1.log|wc -l) -ne 0 ];then
    echo "error"
fi

即使檔案「1.log」不存在,也沒關係,因為第一個條件為假,所以不會評估第二個條件。

答案4

我本來可以將此放在評論中,但目前還不允許。

我注意到 [] 和 [[]] 之間的一個區別是,前者可以使用多重比較。

相同的比較會在 [[]] 中引發語法錯誤

a=1
b=2

這有效:

$  [ "$a" -gt 0 -a "$b" -gt "$a" ] && { echo '[b>a>0]'; }
[b>a>0]

這不起作用:

$ [[ $a -gt 0 -a $b -gt $a ]] && { echo '[[b>a>0]]'; }
-bash: syntax error in conditional expression
-bash: syntax error near `-a'

我還沒有真正深入了解為什麼會這樣,但在使用多重比較時,我使用 []。

相關內容