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)

2
  • Use a shell that supports floating-point, like korn shell. Almost ANY language other than bash supports floating point. Commented Apr 10, 2015 at 6: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 ] Commented Feb 25, 2022 at 15:55

3 Answers 3

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
Sign up to request clarification or add additional context in comments.

3 Comments

Quote the evaluation to avoid word splitting if [ "$(echo "$wpm > 0.06" | bc)" -eq 1 ]; then. (according to shellcheck)
@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"
Indeed. If the input parameter is uncertain/varying, that's a better solution.
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.

4 Comments

Ok thanks. The awk example would be greatly appreciated. I am not familiar with awk at all
I have updated with an example script, but you don't really explain what you are trying to do, so it is very tentative.
Thanks for the awk script example. Sorry for the lack of documentation :/
Updated to read a single parameter and do calculations on that
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

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.