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

33,236

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
Share:
33,236

Related videos on Youtube

yael
Author by

yael

Updated on September 18, 2022

Comments

  • yael
    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
    
  • Stéphane Chazelas
    Stéphane Chazelas over 11 years
    You 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
    peterph over 11 years
    +1, consider if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else. Less typing, less error-prone.
  • Stéphane Chazelas
    Stéphane Chazelas over 8 years
    👍 I like the way you think outside/around the box.
  • mikeserv
    mikeserv over 8 years
    @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.
  • Ken Sharp
    Ken Sharp over 6 years
    @peterph It also takes longer to run.