2016-11-30 72 views
3

我想解釋一下如何在bash條件表達式中最好地使用變量[[...]]如何在bash條件表達式中使用變量?

我平時寫這樣if聲明:

var=1; 
# some code... 
if [[ $var -eq 1 ]]; then echo "ok"; else echo "fail"; fi 

,這回ok如我所料。

現在我在一些腳本中所看到的一樣同樣類似的聲明:

var=1; 
# some code... 
if [[ var -eq 1 ]]; then echo "ok"; else echo "fail"; fi 

唯一的區別是在條件表達式[[...]]缺少的參數擴展字符$

我真的希望這個語句給出一個錯誤,但是這個語法被接受並且返回ok字符串。

我測試使用bash(GNU的bash,版本46年3月4日),zsh(5.1.1),ksh(93u + 2012-08-01)和busybox的ash(BusyBox的v1.23.2)這一說法。

我只能用busybox的外殼得到一個錯誤:

ash: var: bad number 

我在bash手冊頁看到,在ARITHMETIC EVALUATION段,即:

內的表達式,shell變量也可能是通過名稱引用而不使用參數擴展語法

但是我沒有發現任何特別的rel參見CONDITIONAL EXPRESSIONS段落中的參數擴展。

那麼,在引用變量時,條件表達式是否應該包含$?爲什麼?

+0

'if [[var -eq 1]];然後回顯「OK」;否則回顯「失敗」; fi'在'bash'和'ksh'上爲我打印'失敗' – anubhava

+0

@anubhava .. echo $ var返回什麼? :) – ghoti

+0

'declare -p var'顯示我 '-bash:declare:var:not found' – anubhava

回答

3

這裏的觸發器是-eq;因爲它被定義爲執行整數比較,所以它的操作數在算術上下文中被評估。雖然這沒有明確記錄。不過,您應該使用$[[是一個擴展,所以不能保證它在每個定義這樣的構造的shell中表現得完全相同。事實上,我甚至不會假定[[ var -eq 3 ]]將繼續在同一個shell的未來版本中以這種方式運行。 ((var == 3)),但是,由於您處於明確的算術環境中,因此被記錄爲執行var的擴展。

1

檢查bash手冊頁上Compound Commands的部分。具體而言,以下幾點:

((expression)) 
      The expression is evaluated according to the rules described below 
      under ARITHMETIC EVALUATION. If the value of the expression is non-zero, 
      the return status is 0; otherwise the return status is 1. This is exactly 
      equivalent to `let "expression"`. 

    [[ expression ]] 
      Return a status of 0 or 1 depending on the evaluation of the conditional 
      expression expression. Expressions are composed of the primaries 
      described below under CONDITIONAL EXPRESSIONS. 

如果您正在評估需要運算,使用算術運算評估,並檢查CONDITIONAL EXPRESSIONS節你可以用[[ ... ]]做各種事情的東西。雙方括號中的條件可以評估字符串和整數,有時候它們的工作方式是相同的,有時候不會。

從bash的手冊頁,下CONDITIONAL EXPRESSIONS

string1 == string2 
    string1 = string2 
      True if the strings are equal. = should be used with the test command for POSIX conformance. When used with the [[ command, this performs pattern 
      matching as described above (Compound Commands). 
... 
    arg1 OP arg2 
      OP is one of -eq, -ne, -lt, -le, -gt, or -ge. These arithmetic binary operators return true if arg1 is equal to, not equal to, less than, less than 
      or equal to, greater than, or greater than or equal to arg2, respectively. Arg1 and arg2 may be positive or negative integers. 

顯然,字符串 「1」 是字符串 「1」,所以如果n=1,和你比較$n對字符串"1",你會得到一擊。但是你應該知道你在做什麼,而這不是一個數字比較。同樣,<>不是數字比較,它們是字符串比較。所以雖然"1" < "2",你也可能會驚訝"11" < "2"以及。

也就是說,bash的是寬容有關什麼樣的條件,你問它來評價:

bash-4.4$ n=1 
bash-4.4$ [[ n -eq 1 ]] && echo yes 
yes 
bash-4.4$ [[ $n -eq 1 ]] && echo yes 
yes 
bash-4.4$ ((n == 1)) && echo yes 
yes 
bash-4.4$ ((n = 2)) && echo yes 
yes 
bash-4.4$ echo "$n" 
2 

的第一個作品,因爲n不能是什麼,但在這種情況下一個變量,所以慶典將把它因此。但是你不應該依賴這種行爲。在條件表達式中使用美元符號作爲變量,並堅持使用bash的口頭禪,「總是引用你的變量」。

在bash中的雙方括號表達式中,如果打算比較爲整數,則應使用算術二元運算符。

請注意,您的busybox版本似乎使用ash,這不是bash。 Ash是「Almquist shell」,是80年代後期寫成的比POSIX更早的POSIX shell。 Ash是FreeBSD中的/bin/sh的基礎,除了在嵌入式系統(因此busybox)中比bash更受歡迎之外,由於其體積較小。

您可能需要考慮編寫POSIX shell腳本而不是Bash shell腳本。這將意味着簡化一些事情,併爲其他人跳過一些箍。 POSIX不包括雙方括號表達式,但它確實允許諸如[ "$n" -eq 1 ][ $((n + 1)) -eq 2 ]之類的東西。它會在busybox中工作。 :)