Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

239
Views
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.

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
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

The GNU bash man page for [[..]] explains that the operator runs a conditional expression and

Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. 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, i.e.

(( $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 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.

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 e.g. say n=1

$(( 1 < 3 ))
1
[[ -n 1 ]]

So long story short, use the right operands for arithmetic operation inside [[..]].

over 4 years ago · Santiago Trujillo Report

0

(( 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
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!