case + how to implement equal or less or greater in case syntax

case is only for pattern matching, it won't do arithmetic evaluation (except maybe if you consider zsh's <x-y> extended pattern matching operator). The [...] is only to match one character (or collating element in some implementations) based on the set specified within. So for instance [0-80] would match one character if it's one of 0 to 8 or 0 (that is, one of 0, 1, 2, 3, 4, 5, 6, 7, 8).

You could match numbers with patterns like:

case $(($number)) in
  ([0-9]|[1-7][0-9]|80) echo ">=0<=80";;
  (8[1-9]|9[0-9]|100) echo ">=81<=100";;
  ... and so on
esac

But you can easily see that it's not the right tool.

The [...] matches one character against the list of specified characters, so [121-300] matches for any character that is either 1, 2, 1 to 3, 0 or 0, so it's the same as [0-3] or [0123].

Use:

if [ "$number" -ge 0 ] && [ "$number" -le 80 ]; then
  echo ">=0<=80"
elif [ "$number" -ge 81 ] &&  [ "$number" -le 100 ]; then
  echo ">=81<=100"
elif ... and so on
  ...
fi

Another way to use case would be like:

case $((
  (number >= 0 && number <= 80)   * 1 +
  (number > 80 && number <= 100)  * 2 +
  (number > 100 && number <= 120) * 3 +
  (number > 120 && number <= 300) * 4)) in
  (1) echo ">=0<=80";;
  (2) echo ">=81<=100";;
  (3) echo ">=101<=120";;
  (4) echo ">=121<=300";;
  (0) echo "None of the above";;
esac

Or use the ternary operator (x ? y : z):

case $((
  number >= 0 && number <= 80   ? 1 :
  number > 80 && number <= 100  ? 2 :
  number > 100 && number <= 120 ? 3 :
  number > 120 && number <= 300 ? 4 : 0)) in...

Or like @mikeserv, think outside the box, reverse the case logic and match 1 against the value of those arithmetic comparisons.


Actually this is really easy to do. The thing about case is that it will always expand only as much as is needed to find the first match against a pattern. That's spec'd behavior. And so you can just set it up with a known string and evaluate the patterns' expansions.

case  1:${number:--} in
(1:*[!0-9]*|1:0*[89]*)
  ! echo NAN
;;
($((number<81))*)
    echo "$number >=0<=80"
;;
($((number<101))*)
    echo "$number >=81<=100"
;;
($((number<121))*)
    echo "$number >=101<=120"
;;
($((number<301))*)
    echo "$number >=121<=300"
;;
esac

case will never expand any more of those patterns than it has to in order to find a leading 1 in the pattern. This is especially important when working with user input, because it means you can safely verify the contents of $number before ever trying to put it in an arithmetic expansion context in the same case statement in which you actually do put it in a math expansion.