3

I am trying to use bc to compare a value with decimals in my if statement. I am not sure if I am using bc correctly in my if statement because it doesn't seem to work. It always enters the 4th if statement "IF4". It doesn't seem like the other conditions are being read properly?

 #SET INITIAL SPEED
initialspeed() {

wpm=0
echo wpm: $wpm
#CHECKS IF SPEED WAS GIVEN
if [ -z "$wpm" ]
then
        let wpm=0.6
        echo IF1 wpm: $wpm #DEBUG
#CHECK IF SPEED IS VALID
elif [ 'echo "if$($wpm > 0.6)1;if$($wpm<=0.6)0" | bc' = 1 ]
then
        echo IF2 wpm: $wpm #DEBUG
        echo Error speed is less than 100 wpm
        exit 3
elif [ 'echo "if$($wpm < 0.06)1;if$($wpm<=0.06)0" | bc' = 1 ]
then
        echo IF3 wpm: $wpm #DEBUG
        echo Error speed is more than 1000 wpm
exit 3
else
        wpm=$(echo "scale=2;60/$2 | bc")
        echo IF4 wpm: $wpm #DEBUG
fi
}

EDIT: I am actually trying to write a script similar to the "spritz" speed reader. $1 is the file to be read and $2 is the speed that the words will be displayed to the screen. $2 is am optional argument if its not given I set a default speed.

The speed given should be between 100 and 1000 wpm (0.6 and 0.06 before the calculation)

hotlinks0
  • 101
  • 4
  • 12
  • Use a shell that supports floating-point, like korn shell. Almost ANY language other than bash supports floating point. – cdarke Apr 10 '15 at 06:19
  • The `let` keyword is incompatible with float values, it is integer only. Also, the `[ ' command ' = 1 ]` uses single quotes, which are for constants and wont be evaluated. Use `"$()"` around the `bc` evaluation, like `elif [ "$(echo "if$($wpm > 0.6)1;if$($wpm<=0.6)0" | bc)" = 1 ]` – andiOak Feb 25 '22 at 15:55

3 Answers3

5

You can pipe your test into bc with

echo "$wpm > 0.06" | bc

Testing the result is possible with

if [ $(echo "$wpm > 0.06" | bc) -eq 1 ]; then
    echo "You are going to fast"
else
    echo "Slow"
fi
Walter A
  • 19,067
  • 2
  • 23
  • 43
  • Quote the evaluation to avoid word splitting `if [ "$(echo "$wpm > 0.06" | bc)" -eq 1 ]; then`. (according to shellcheck) – andiOak Feb 23 '22 at 21:27
  • @andiOak You are right that `wpm=2 3 4` will make my solution break. Since `echo "$wpm > 0.06" | bc` will break, your improvement won't help. We need to check `wpm` first. Something like `[[ $wpm =~ ^[0-9]+[.]?[0-9]* ]] || echo "wrong format"` – Walter A Feb 24 '22 at 21:39
  • 1
    Indeed. If the input parameter is uncertain/varying, that's a better solution. – andiOak Feb 25 '22 at 15:31
3

You are attempting to use process substitution, but you have single quotes instead of backticks. Text inside of single quotes is just a literal string to Bash. You are looking for backticks:

if [ `command` = "result" ]; then  # notice `command` vs 'command'

but the preferred, modern syntax is

if [ $(command) = "result" ]; then

but this is still rather convoluted -- usually, you want something like

if command; then

where maybe command is a slightly more complex thing than you had originally.

In this particular case, I would wrap your logic in a simple Awk script instead.

You are expected to call this with the wpm value; if it is missing, a default of 0.6 is supplied.

initialspeed() {
    local wpm
    wpm=${1:-0.6}
    echo "wpm: $wpm" >&2 # notice quoting
    echo "$wpm" | awk '$1 > 0.6 {
            print "Error: speed $1 is less than 100 wpm" >"/dev/stderr"; exit 3 }
        $1 < 0.06 {  # You had < 0.06 vs <= 0.06 but I guess this is what you meant
            print "Error: speed $1 is more than 1000 wpm" >"/dev/stderr"; exit 3 }
        { printf "%2.2f\n", 60/$1 }'
}

Your original script apparently has the wrong comparison for the value 0.06. Looking at it now, I'm guessing you actually want the value to be between 0.06 and 0.6, inclusive; but in any event, this is just a sketch for you to work from.

tripleee
  • 175,061
  • 34
  • 275
  • 318
0

If you intention is to return 0 or 1 depending on wpm value you would need something like this

echo "if ( $wpm > 0.6 ) 1 else 0" | bc
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • I am returning 1 or 0 just to determine if wpm is greater than or less than a specific value and then comparing the if statement to the 1 instead of a float – hotlinks0 Apr 10 '15 at 05:10