Gabsii
Gabsii

Reputation: 456

bash - Integer expression expected

I wanted to simulate a vending machine where you can buy things only if you throw 2€ inside.

It works as long as i only enter integer values, but if i enter a character or a float it suddenly stops to work. And throws an error that there is an integer expression expected.

read -p "Throw in money" x
echo ""

while [ $x -ne 2 ] ;
do
case $x in
        0.5)
                read -p "more money" z
                x=$(($x + $z))
                ;;
        1)
                read -p "more money" z
                x=$(($x + $z))
                ;;
        1.5)
                read -p "more money" z
                x=$(($x + $z))
                ;;
        "R")
                echo "return x"
                x=0
                ;;
        ?)
                echo "enter something else!"
                x=0
                ;;
esac
done

Upvotes: 1

Views: 2931

Answers (3)

ilkkachu
ilkkachu

Reputation: 6537

Bash can only do arithmetic with integers, as stated in the manual.

To do floating point arithmetic, you'd need to do something like piping to bc:

$ x=1.0; z=0.5
$ bc <<< "$x + $z"
1.5

Comparisons work, sort of, you need to read the output to get the truth value:

$ bc <<< "$x < 1.5"
1

Other choices would be to convert the floats to another internal representation, e.g. counting cents instead of full dollars/euros. Or convert the script to something like zsh, awk or Perl, which can deal with floats.


Here's a sketch for cent-based counting:

#!/bin/bash
total=0
getcoin() {

        read -p "Insert coin: " x
        case $x in
        0.1)    cents=10 ;;
        0.2)    cents=20 ;; 
        0.5)    cents=50 ;;
        1|1.0)  cents=100 ;;
        2|2.0)  cents=200 ;;
        *)      echo "Invalid coin!"; return 0;;
        esac
        (( total = total + cents))
        return 0;
}

while getcoin && [[ $total -lt 200 ]] ; do
        printf "You have %d cents\n" "$total"
done
printf "You got %d.%02d € in total\n" $((total / 100)) $((total % 100))

Upvotes: 0

chepner
chepner

Reputation: 531718

-ne only does integer comparisons, so $x must expand to something that the shell recognizes as an integer. Just switch to != and compare as a string. Further, since bash cannot add floating point values either, you'll need to use something like bc to do the addition.

while [ "$x" != 2 ] ;
do
  case $x in
        0.5)
                read -p "more money" z
                x=$( bc <<< "$x + $z" )
                ;;
        1)
                read -p "more money" z
                x=$( bc <<< "$x + $z" )
                ;;
        1.5)
                read -p "more money" z
                x=$( bc <<< "$x + $z" )
                ;;
        "R")
                echo "return x"
                x=0
                ;;
        ?)
                echo "enter something else!"
                x=0
                ;;
  esac
done

Upvotes: 2

FrankTheTank_12345
FrankTheTank_12345

Reputation: 580

One approach is to use a regular expression, like so:

re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo "error: Not a number" >&2; exit 1
fi

Upvotes: 0

Related Questions