-1

In the below code, ShellCheck throws an error in the while clause.

count=10.0
while [ $count -le 20.0 ]
do
    echo "Hello"
    count=$(bc<<< "scale=4; (count+0.1)")
done

ShellCheck says:

Decimals not supported, either use integers or bc

I am not quite sure how to use bc in a while loop.

while [ $(bc <<< "scale=4; (count -le 20.0)" ]

How do I compare decimal numbers in a while clause? Any advice?

Will
  • 24,082
  • 14
  • 97
  • 108
anishjp
  • 115
  • 3
  • 13

3 Answers3

4

Bash doesn't support floating point arithmetic. You can either use bc:

count="10.0"
limit="12.0"
increment="0.1"

while [ "$(bc <<< "$count < $limit")" == "1"  ]; do
    echo "Hello"
    count=$(bc <<< "$count+$increment")
done

or awk:

while awk 'BEGIN { if ('$count'>='$limit') {exit 1}}'; do
    echo "Hello"
    count=$(bc <<< "$count+$increment")
done

I just wonder: why not (directly) count from 10.0 to 12.0 ?

for i in $(seq 10.0 0.1 12.0); do
    echo "Hello"
done
1

Bash doesn't support floating pointing arithmetic. You can use bc for that comparison too:

count=10.0

while : ;
do
    out=$(bc -l<<< "$count<20.0")
    [[ $out == 0 ]] && { echo "Reached limit" ; exit 0; }

    echo "Hello"
    count=$(bc<<< "scale=4; ($count+0.1)")
done

Note that I added the missing $ to count inside the loop where you update count.

P.P
  • 117,907
  • 20
  • 175
  • 238
0

While bash doesn't handle floating point numbers, the seq utility does. [Note 1]

The basic syntax is seq FIRST INCREMENT LAST, so in your case you could use

for count in "$(seq 10.0 0.1 20.0)"; do
  # something with $count
done

If you provide two arguments, they are assumed to be FIRST and LAST, with INCREMENT being 1. If you provide only one argument, it is assumed to be LAST, with both FIRST and INCREMENT being 1. As in your example, the sequence is inclusive so both FIRST and LAST will be produced provided that INCREMENT evenly divides FIRST−LAST.

You can also include an explicit format:

$ seq -f "%06.3f" 1 .5 2
01.000
01.500
02.000

One downside of this technique is that it precomputes the entire collection of values. If the loop will execute hundreds of thousands of times, that might use up a lot of memory, in which case you could use a pipe or process substitution instead:

while read count; do
  # something with count
done < <(seq 10.0 0.000001 20.0)

Notes

  1. seq is not Posix but it is almost always present; it's part of GNU coreutils and a similar utility, available in Mac OS X) has been in NetBSD since 3.0 and FreeBSD since 9.0.
Community
  • 1
  • 1
rici
  • 234,347
  • 28
  • 237
  • 341