[英]Why doesn't Bash `(())` work inside `[[]]`?
[[ " stop start status " =~ " $2 " && (($#<3)) ]] || { echo "Usage $0 file_name command"; exit 1;}
我經常使用上述解決方案來檢查我的 Bash 腳本的輸入范圍。
現在我意識到擴展的算術表達式(())
看起來像是被抑制在雙括號[[]]
內。
為了說明問題:
a=start; n=1; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad
ok
a=start; n=5; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad
bad
# But:
a=start; n=100; [[ " stop start status " =~ " $a " && (($n<3)) ]] && echo ok || echo bad
ok
上述結果是錯誤的,因為如果將它們視為數字,則 n 不小於 3。 這是正確的解決方案:
a=start; n=100; [[ " stop start status " =~ " $a " ]] && (($n<3)) && echo ok || echo bad
bad
a=start; n=1; [[ " stop start status " =~ " $a " ]] && (($n<3)) && echo ok || echo bad
ok
[[..]]
的 GNU bash 手冊頁解釋說,運算符運行條件表達式和
根據條件表達式
expression
的計算返回狀態0
或1
。 表達式由下面Bash 條件表達式中描述的基元組成。
但是算術運算符不是[[..]]
內支持的條件表達式( primaries )的一部分,這意味着表達式被迫作為字符串比較運行,即
(( $n < 3))
不是在算術上下文中運行,而是像普通的字典(字符串)比較一樣
[[ 100 < 3 ]]
這將始終為真,因為1
、 0
、 0
的 ASCII 值出現在3
之前
但是如果使用-lt
, -gt
,則支持[[..]]
內部算術運算
arg1 OP arg2
OP 是
-eq
、-ne
、-lt
、-le
、-gt
或-ge
之一。 如果arg1
分別等於、不等於、小於、小於或等於、大於或大於或等於arg2
,則這些算術二元運算符返回 true。
所以你有沒有把你的表達寫成
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad
它會按預期工作。
或者,即使您通過在((..))
之前添加$
前綴來強制使用算術表達式並將其編寫如下(注意 bash 在[[..]]
內沒有記錄$((..))
的行為) . 可能的預期行為是在評估[[..]]
之前擴展算術表達式,並且在字符串上下文中將結果 output 評估為[[ 0 ]]
,這意味着非空字符串。
a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad
結果看起來仍然很糟糕,因為[[..]]
內的算術表達式分解為一元字符串而不是空比較表達式
$(( 5 < 3 ))
0
[[ -n 0 ]]
算術評估的結果0
(false) 被測試運算符視為非零實體,並在&&
的右側斷言 true。 這同樣適用於其他情況,例如說n=1
$(( 1 < 3 ))
1
[[ -n 1 ]]
長話短說,在[[..]]
中使用正確的操作數進行算術運算。
((
是引入算術語句的“關鍵字”。但是,在[[
內部,您不能使用其他語句。但是,您可以使用括號對表達式進行分組,這就是((... ))
的含義:冗余“雙組”。由於<
和&&
的優先級,以下都是等價的:
[[ " stop start status " =~ " $2 " && (($#<3)) ]]
[[ " stop start status " =~ " $2 " && ($#<3) ]]
[[ " stop start status " =~ " $2 " && $#<3 ]]
如果您想要 integer 比較,請使用-lt
而不是<
,但您也不需要將所有內容都放入[[... ]]
。 您可以在命令列表中同時使用條件語句和算術語句。
{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}
在這種情況下, ... &&... ||...
將按照您期望的方式工作,但通常情況並非如此。 更喜歡if
語句。
if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
echo "Usage $0 file_name command"
exit 1
fi
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.