case + how to implement equal or less or greater in case syntax
Solution 1
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.
Solution 2
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.
Solution 3
This is not very nice but you can use this :
#!/bin/ksh
read number
case $number in
[0-9]|[1-7][0-9]|80) echo echo ">=0<=80";;
8[1-9]|9[0-9]|100) echo ">=81<=100";;
10[1-9]|11[0-9]|120) echo ">=101<=120";;
12[1-9]|130) echo ">=121<=300";;
esac
Related videos on Youtube
yael
Updated on September 18, 2022Comments
-
yael almost 2 years
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 read number case $number in [0-80]) echo ">=0<=80";; [81-100]) echo ">=81<=100";; [101-120]) echo ">=101<=120";; [121-300]) echo ">=121<=300";; esac
- If the number is between 0 and 80, print
-
Stéphane Chazelas over 11 yearsYou may want to "canonify" the number with $(($number)) to cover for numbers like "001" or "0x99"... That would also cover for " 12" and "12+12" which may or may not be desirable.
-
peterph over 11 years+1, consider
if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else
. Less typing, less error-prone. -
Stéphane Chazelas over 8 years👍 I like the way you think outside/around the box.
-
mikeserv over 8 years@StéphaneChazelas - i like
case
. theres some cool stuff you can do with$((
math))
andcase
- 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 analias
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. -
Ken Sharp over 6 years@peterph It also takes longer to run.