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.