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

My target is to verify a range of number with (only with `case` + `esac`), and print the range. So for example:

• If the number is between 0 and 80, print `>=0<=80`
• If the number is between 81 and 100 then print `>=81<=100`
• etc.

The problem with my script below print only `>=0<=90` only if the number between 0 and 9. How to fix my script, so that it will print correct output according to the number range?

``````#!/bin/ksh
case \$number in
[0-80])  echo ">=0<=80";;
[81-100]) echo ">=81<=100";;
[101-120]) echo ">=101<=120";;
[121-300]) echo ">=121<=300";;
esac
``````
-

`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.

-
+1, consider `if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else`. Less typing, less error-prone. – peterph Feb 19 '13 at 12:29

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.

-
👍 I like the way you think outside/around the box. – Stéphane Chazelas Oct 29 '15 at 20:41
@StéphaneChazelas - i like `case`. theres some cool stuff you can do with `\$((`math`))` and `case` - especially surrounding assignments in patterns that never happen until they need to - and you can even build parse trees that expand nested recursions if you populate the patterns with an `alias` chain. its the fastest way ive found to get a shell to do stuff like character translation and to swap characters for bytes values. it can be pretty fast - C-Locale ASCII+ <> octal very worst case is 7 basic POSIX pattern expansions. – mikeserv Oct 29 '15 at 21:08

This is not very nice but you can use this :

`````` #!/bin/ksh