[英]Why doesn't Bash `(())` work inside `[[]]`?
[[ " stop start status " =~ " $2 " && (($#<3)) ]] || { echo "Usage $0 file_name command"; exit 1;}
I frequently use the above solution to check the input range of my Bash script.我经常使用上述解决方案来检查我的 Bash 脚本的输入范围。
Now I realise that the extended arithmetic expression (())
looks like it is suppressed inside the double bracket [[]]
.现在我意识到扩展的算术表达式
(())
看起来像是被抑制在双括号[[]]
内。
To illustrate the problem:为了说明问题:
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
The above result is false because n not less than 3 if they are treated as numbers.上述结果是错误的,因为如果将它们视为数字,则 n 不小于 3。 This is the correct solution:
这是正确的解决方案:
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
The GNU bash man page for [[..]]
explains that the operator runs a conditional expression and [[..]]
的 GNU bash 手册页解释说,运算符运行条件表达式和
Return a status of
0
or1
depending on the evaluation of the conditional expressionexpression
.根据条件表达式
expression
的计算返回状态0
或1
。 Expressions are composed of the primaries described below in Bash Conditional Expressions .表达式由下面Bash 条件表达式中描述的基元组成。
But the arithmetic operator is not part of the supported conditional expressions ( primaries ) inside [[..]]
which means the expression is forced to run as a string comparison, ie但是算术运算符不是
[[..]]
内支持的条件表达式( primaries )的一部分,这意味着表达式被迫作为字符串比较运行,即
(( $n < 3))
is not run in arithmetic context but just as plain lexicographic (string) comparison as不是在算术上下文中运行,而是像普通的字典(字符串)比较一样
[[ 100 < 3 ]]
which will always result true, because the ASCII values for 1
, 0
, 0
appear before 3
这将始终为真,因为
1
、 0
、 0
的 ASCII 值出现在3
之前
But inside [[..]]
arithmetic operations are supported if you use -lt
, -gt
但是如果使用
-lt
, -gt
,则支持[[..]]
内部算术运算
arg1 OP arg2
OP is one of
-eq
,-ne
,-lt
,-le
,-gt
, or-ge
.OP 是
-eq
、-ne
、-lt
、-le
、-gt
或-ge
之一。 These arithmetic binary operators return true ifarg1
is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal toarg2
, respectively.如果
arg1
分别等于、不等于、小于、小于或等于、大于或大于或等于arg2
,则这些算术二元运算符返回 true。
So had you written your expression as所以你有没有把你的表达写成
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad
it would have worked as expected.它会按预期工作。
Or even if you had forced the arithmetic expression usage by prefixing $
before ((..))
and written it as below (note that bash does not have documented behavior for $((..))
inside [[..]]
).或者,即使您通过在
((..))
之前添加$
前缀来强制使用算术表达式并将其编写如下(注意 bash 在[[..]]
内没有记录$((..))
的行为) . The likely expected behavior is the arithmetic expression is expanded before the [[..]]
is evaluated and the resultant output is evaluated in a string context as [[ 0 ]]
which means a non-empty string.可能的预期行为是在评估
[[..]]
之前扩展算术表达式,并且在字符串上下文中将结果 output 评估为[[ 0 ]]
,这意味着非空字符串。
a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad
The result would still look bad, because the arithmetic expression inside [[..]]
decomposes into an unary string not empty comparison expression as结果看起来仍然很糟糕,因为
[[..]]
内的算术表达式分解为一元字符串而不是空比较表达式
$(( 5 < 3 ))
0
[[ -n 0 ]]
The result of the arithmetic evaluation 0
(false) is taken as a non-zero entity by the test operator and asserts true on the right-side of &&
.算术评估的结果
0
(false) 被测试运算符视为非零实体,并在&&
的右侧断言 true。 The same would apply for the other case also eg say n=1
这同样适用于其他情况,例如说
n=1
$(( 1 < 3 ))
1
[[ -n 1 ]]
So long story short, use the right operands for arithmetic operation inside [[..]]
.长话短说,在
[[..]]
中使用正确的操作数进行算术运算。
((
is a "keyword" that introduces the arithmetic statement. Inside [[
, however, you can't use other statements. You can use parentheses to group expressions though, so that's what ((... ))
is: a redundant "double group". The following are all equivalent, due to the precedences of <
and &&
: ((
是引入算术语句的“关键字”。但是,在[[
内部,您不能使用其他语句。但是,您可以使用括号对表达式进行分组,这就是((... ))
的含义:冗余“双组”。由于<
和&&
的优先级,以下都是等价的:
[[ " stop start status " =~ " $2 " && (($#<3)) ]]
[[ " stop start status " =~ " $2 " && ($#<3) ]]
[[ " stop start status " =~ " $2 " && $#<3 ]]
If you want integer comparison, use -lt
instead of <
, but you also don't need to fit everything inside [[... ]]
.如果您想要 integer 比较,请使用
-lt
而不是<
,但您也不需要将所有内容都放入[[... ]]
。 You can use a conditional statement and an arithmetic statement together in a command list.您可以在命令列表中同时使用条件语句和算术语句。
{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}
In this case, ... &&... ||...
will work the way you expect, though in general that is not the case.在这种情况下,
... &&... ||...
将按照您期望的方式工作,但通常情况并非如此。 Prefer an if
statement instead.更喜欢
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.