2

I have this simple comparison operator, it check if number is between 1 and 3 (1 and 3 included too). But if I assign number to 3,2 it still accepts as correct.

It should only accept those values 1-2-3

My code

if (("$number" >= 1 && "$number" <= 3)); then
echo 'Correct number'
fi
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
kftavoyz
  • 71
  • 5
  • 1
    can you clarify that the assignment is really `number=1,2` and `number=3,2` Please put the assignment in you question/post. – Jetchisel Jun 13 '21 at 11:27

3 Answers3

6

(("$number" >= 1 && "$number" <= 3)) is a Bash's stand-alone arithmetic expression.

Within an arithmetic expression, variables are expanded as-is and if they contain valid arithmetic expression's syntax elements, these are also interpreted.

number="3,2" expands as ((3,2)) in an arithmetic expression, where comma , is interpreted as a statements separator by Bash's arithmetic expressions.

Lets see:

$ number="3,2"; echo "$((number))"
2
$ number="3+2"; echo "$((number))"
5
$ number="3*2"; echo "$((number))"
6

The shell only understands integer arithmetic, but 3,2 is not a valid integer value.

It means that if you are unsure a variable contains a valid integer, it is unsafe for use within an arithmetic expression.

Always check that number contains a valid integer (see: Test whether string is a valid integer) before using in an arithmetic expression or within a test comparing integers.

# Check number is a valid integer before testing its range.
[[ $number =~ ^[-+]?[0-9]+$ ]] && (("$number" >= 1 && "$number" <= 3))

The other numeric test method [ "$number" -ge 1 ] && [ "$number" -le 3 ] as suggested in the other answers will error-out with: bash: [: 3,2: integer expression expected.

It also needs testing for valid integer:

[[ $number =~ ^[-+]?[0-9]+$ ]] && [ "$number" -ge 1 ] && [ "$number" -le 3 ]

With POSIX shell, there is no Regex test, so a different approach is needed:

case "${number#[+-]}" in(*[!0123456789]*|'')false;;esac &&
  [ "$number" -ge 1 ] && [ "$number" -le 3 ]

An additional note about the pitfalls of using arithmetic expressions to compare numbers. Arithmetic expressions will handle leading 0 of an integer, as an octal:

$ (( 13 >= 12 )); echo $?
0

but

$ (( 013 >= 12 )); echo $?
1
Léa Gris
  • 17,497
  • 4
  • 32
  • 41
5

Try this:

if [ "$number" -ge 1 ] && [ "$number" -le 3 ]; then 
echo 'Correct number'
fi
Mikołaj Głodziak
  • 4,775
  • 7
  • 28
  • This will error-out when `number="3,2"`, with: `bash: [: 3,2: integer expression expected`. You have to check that `number` contains a valid integer. – Léa Gris Jun 13 '21 at 16:09
4

You have to rewrite your code as follow:

if [ "$number" -ge 1 ] && [ "$number" -le 3 ]; then
    echo 'Correct number'
fi

Look at https://tldp.org/LDP/abs/html/comparison-ops.html for further information.

Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74