[[ " 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.
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. 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
Return a status of
0
or1
depending on the evaluation of the conditional expressionexpression
. Expressions are composed of the primaries described below in Bash Conditional Expressions .
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
(( $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
But inside [[..]]
arithmetic operations are supported if you use -lt
, -gt
arg1 OP arg2
OP is one of
-eq
,-ne
,-lt
,-le
,-gt
, or-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.
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 [[..]]
). 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.
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 &&
. The same would apply for the other case also eg say 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 [[... ]]
. 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 [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
echo "Usage $0 file_name command"
exit 1
fi
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.