1

Have tried several different syntax methods to make bash test between number ranges for floating point numbers and cannot get this to work. Whole numbers work, so do statements without the && operator. I must be missing something obvious.

Essentially 70 and below is "ok", between 70.1 and 79.9 is "warn", 80 and above is "critical"

Thanks in advance for any help or advice.

#! /bin/bash

number=70.1
echo $number

if (( $(echo "$number < 70" | bc -l) )); then echo "OK";fi
if (( $(echo "$number >= 70" && "$number < 80" | bc -l) )); then echo "WARN";fi
if (( $(echo "$number >= 80" | bc -l) )); then echo "CRITICAL";fi
3
  • bash doesn't support floating point. Commented May 16, 2020 at 11:18
  • 2
    If the boundaries of your range are whole numbers, why do you need to compare fractions? Commented May 16, 2020 at 11:19
  • @Barmar comparing with turning floating-point number to an integer only works for positive values. (See the note from my answer) Commented May 16, 2020 at 13:13

3 Answers 3

2

echo "$number >= 70" && "$number < 80" are two commands in bash. The first is echo and the second command is "70.1 < 80" (pretty sure there is no such command on your system).

You probably wanted to write echo "$number >= 70 && $number < 80" which is just one command.

By the way: In bash you can use bc <<< ... instead of echo ... | bc.

if (( $(bc <<< "$number < 70") )); then echo "OK"; fi
if (( $(bc <<< "$number >= 70 && $number < 80") )); then echo "WARN"; fi
if (( $(bc <<< "$number >= 80") )); then echo "CRITICAL"; fi

or with restructured control flow

if (( $(bc <<< "$number < 70") )); then
  echo "OK";
elif (( $(bc <<< "$number < 80") )); then
  echo "WARN"
else
  echo "CRITICAL"
fi
Sign up to request clarification or add additional context in comments.

1 Comment

solved my problem and a very clear explanation too. Thanks for helping out, I changed to the control flow option you provided as the final solution.
1

This should be a single awk command.

awk -v n="$number" 'BEGIN {
  if      (n < 70) { print "OK"; }
  else if (n < 80) { print "WARN"; }
  else             { print "CRITICAL"; }
}'

5 Comments

Instead of awk -v n="$number" 'BEGIN { ... n ... }' you could also use the slightly hacky but shorter and more portable version awk '{ ... $0 ... }' <<< "$number".
That's quite a bit less portable: <<< is a shell-specific extension to the POSIX standard. This answer uses no extensions to the POSIX standard for awk.
Oh wow, I always thought -v was a GNU extension. Seems I was wrong. Thank you for pointing this out. ¶ I don't see <<< as a portability problem here as OP explicitly wrote #! /bin/bash.
thanks, I confirmed this solved my issue. I went with the other solution as I was already using bc. Good to know awk can be used in this way.
@Socowi There's also a marginal performance issue. A here-string is just syntactic sugar for a one-line here document, and here documents are implemented as temporary files. The awk command isn't doing any I/O at all.
0

Since the comparison ranges are positive integers¹, these can be compared natively by the shell if $number is first converted to an integer:

#!/usr/bin/env bash

# Defines the locale of our floating-point numbers
LC_NUMERIC=POSIX
number=70.1
echo $number

declare -i intnum

# Get decimal_point from locale (can be comma or anything locale specific)
dp="$(locale decimal_point)"

# Cut fractional part of floating-point number to a whole integer intnum
intnum="${number%$dp*}"

# Shell natively compares integer
if [ $intnum -lt 70 ]; then
  echo 'OK';
elif [ $intnum -lt 80 ]; then
  echo 'WARN'
else
  echo 'CRITICAL'
fi

  1. The integer comparison only works for positive numbers.
    (-1.1 < -1 but -1 = -1)

2 Comments

But this would print WARN for number=69.9 when it should print OK. To fix the problem you could truncate instead of round. Replace printf by intnum=${number/.*/}. To allow negative numbers you could use bash (( … < … )) instead of posix [ … -lt … ].
@Socowi I just expanded and applied your suggestion with: intnum="${number%.*}"

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.