vato
vato

Reputation: 99

Bash script: testing if floating point number is in a certain range including negative numbers

I'm trying to test if the variable $test is between -0.9 and 0.9. The following code works with numbers, but if $test is a lower case letter, it says it's a number between -0.9 and 0.9.

Is there a better way of doing this, so that letters are not considered to be in the range?

test=a

if (( $( echo "$test >= -0.9" |bc -l) )) && (( $(echo "$test <= 0.9" |bc -l) )); then
    echo "${test} is between -0.9 and 0.9"
else
    echo "${test} is NOT between -0.9 and 0.9"
fi

Upvotes: 2

Views: 1333

Answers (2)

tripleee
tripleee

Reputation: 189628

Refactoring the code to use Awk might be more efficient, though it requires understanding some obscure things about the shell.

if awk -v number="$test" 'END { exit !( \
    number !~ /[^0-9.]/ && number !~ /\..*\./ && \
    number >= -0.9 && number <= 0.9) }' /dev/null
then
    echo "$test is between -0.9 and 0.9"
else
    echo "$test is NOT between -0.9 and 0.9"
fi

The exit code examined by if is regarded as true if it's zero, which is opposite to the truth value inside the parentheses; thus exit !(...). Awk's processing model requires you to read an input file; we supply /dev/null, and put the actual logic in the END block so it gets executed even when there is no input.

This checks that there is never more than one decimal point but the regex doesn't currently cope with exponential notation. Adding support for that should not be too hard, given the regex in John1024's answer.

Upvotes: 0

John1024
John1024

Reputation: 113914

Replace:

if (( $( echo "$test >= -0.9" |bc -l) )) && (( $(echo "$test <= 0.9" |bc -l) )); then

With (assuming GNU or other enhanced bc):

if [[ "$test" =~ ^[[:digit:].e+-]+$ ]] && echo "$test>-0.9 && $test <=0.9" |bc -l | grep -q 1; then

How it works

  • [[ "$test" =~ ^[[:digit:].e+-]+$ ]]

    This checks that $test contains only legal number characters.

  • &&

    This continues the bc test only if $test passed the number check.

  • echo "$test>-0.9 && $test <=0.9" |bc -l | grep -q 1

    This verifies that $test is in the range that you want. grep -q 1 sets the appropriate exit code for the if statement to use.

Upvotes: 1

Related Questions