kftavoyz
kftavoyz

Reputation: 81

Bash value between two integers, NOT floats

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

Upvotes: 2

Views: 325

Answers (3)

L&#233;a Gris
L&#233;a Gris

Reputation: 19615

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

Upvotes: 6

Mikołaj Głodziak
Mikołaj Głodziak

Reputation: 5277

Try this:

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

Upvotes: 5

Antonio Petricca
Antonio Petricca

Reputation: 11030

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.

Upvotes: 4

Related Questions