1
downloadspeed=800.00
dl="$downloadspeed/1" | bc
if [ $((dl)) -lt 500 ]
then
    echo "slow - send slow message"
else
    echo "fast - no issue"
fi

What am I doing wrong? I tried many variations to test the $downloadspeed and this is where I left off. It seems no matter how I test it all is treating my variable as a string. $downloadspeed < 500, $dl < 500, "$dl" < 500, etc. tried so many variations.

Tom
  • 129
  • Try your script in https://www.shellcheck.net/ and see if it helps – Quasímodo Jun 01 '20 at 11:48
  • Also: https://unix.stackexchange.com/questions/40786/how-to-do-integer-float-calculations-in-bash-or-other-languages-frameworks and https://unix.stackexchange.com/questions/24721/how-to-compare-to-floating-point-number-in-a-shell-script – ilkkachu Jun 01 '20 at 11:50
  • @Quasímodo great resource for bash checks, thanks. – Tom Jun 01 '20 at 12:03
  • @ikkachu good resource also, gave some different examples. – Tom Jun 01 '20 at 12:03

2 Answers2

2

The first thing wrong is your assignment to dl:

dl="$downloadspeed/1" | bc

This means "set the variable $dl to the string 800.00/1, and then pass the output of the variable assignment to bc". Since the assignment has no output, the result is just setting dl to 800.00.

BUT, and this is important, pipelines run in their own subshell and any variables set in that subshell won't be available to the parent shell. This means that even if this assignment were actually doing what you wanted it to do, dl would still only be set while that pipeline is running and would be unset in the script itself.

Then, you run this:

if [ $((dl)) -lt 500 ]

This means "if the result of executing the contents of the $dl variable as an arithmetic expression command are less than 500. To do this, you need to set the value of dl to a valid arithmetic expression. For example:

800/1

But what you have is an empty variable since, as mentioned above, the $dl only had a value in the subshell running the pipe.

In any case, this is all really needlessly complicated. Why not do this instead:

#!/bin/sh

downloadspeed=800.00
value=$(printf '%s\n' "$downloadspeed"/1 | bc)
if [ $value -lt 500 ]
then
    echo "slow - send slow message"
else
    echo "fast - no issue"
fi

Next time, to debug such issues, you can use set -x. Add it to the start of your script:

#!/bin/sh
set -x
downloadspeed=800.00
dl="$downloadspeed/1" | bc
if [ $((dl)) -lt 500 ]
then
    echo "slow - send slow message"
else
    echo "fast - no issue"
fi

if you now run your script, you will see exactly what commands are being executed:

$ foo.sh
+ downloadspeed=800.00
+ dl=800.00/1
+ bc
+ '[' 0 -lt 500 ']'
+ echo 'slow - send slow message'
slow - send slow message

As you can see, because $dl is empty but is used inside an arithmetic expression ($(( ))), that is evaluated to 0, and you're actually running [ 0 -lt 500 ], which is always true.

terdon
  • 242,166
  • Excellent, $(printf '%s\n' "$downloadspeed"/1 | bc) was the magic sauce. I am fairly new at some of these scripting syntax in bash. Thanks for showing me how to get that output. – Tom Jun 01 '20 at 12:00
  • "the result is just setting dl to 800.00" ...in the subshell started for the pipeline, so dl is still unset in the main shell, and the arithmetic expression resolves it as zero... – ilkkachu Jun 01 '20 at 14:01
  • @ilkkachu oh damn, yes of course. I had completely missed that, thanks! Answer edited. – terdon Jun 01 '20 at 14:52
1

Just use a shell with floating point arithmetic support like zsh (you're already writing zsh syntax by not quoting your $((dl))) instead of bash and do:

downloadspeed=800.00
if ((downloadspeed < 500))
then
    echo "slow - send slow message"
else
    echo "fast - no issue"
fi

With bash or POSIX sh syntax which don't support floating point arithmetics, you could call awk to do the comparison:

compare() { # args: <number> <op> <number>
  POSIXLY_CORRECT=1 awk -- "
    BEGIN {exit(!((0+ARGV[1]) $2 (0+ARGV[2])))}" "$1" "$3"
}

if compare "$downloadspeed" '<' 500
then
    echo "slow - send slow message"
else
    echo "fast - no issue"
fi

The POSIXLY_CORRECT=1 helps in case your awk is the GNU implementation to make it recognise more forms of numbers (like infinity, 0x10, 0x1p4... YMMV with other implementations). The -- helps with older versions of busybox awk which would otherwise treat negative numbers as options. The 0+ is to force a numeric comparison in things like compare '8 apples' '<' '10 bananas' (where the trailing text is ignored) instead of resorting to string comparison in those cases.