case + como implementar igual ou menor ou maior no caso de sintaxe

9

Minha meta é verificar um intervalo de números com (somente com case + esac ) e imprimir o intervalo. Então, por exemplo:

  • Se o número estiver entre 0 e 80, imprima >=0<=80
  • Se o número estiver entre 81 e 100, imprima >=81<=100
  • etc.

O problema com o meu script abaixo imprime apenas >=0<=90 apenas se o número estiver entre 0 e 9. Como consertar meu script, para que ele imprima a saída correta de acordo com o intervalo de números?

#!/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
    
por yael 19.02.2013 / 11:52

3 respostas

5

case é apenas para correspondência de padrões, não fará avaliação aritmética (exceto, talvez, se você considerar zsh <x-y> extended matching operator). O [...] é apenas para corresponder a um caractere (ou elemento de agrupamento em algumas implementações) com base no conjunto especificado dentro. Portanto, por exemplo, [0-80] corresponderia a um caractere se for um dos 0 a 8 ou 0 (ou seja, um dos 0, 1, 2, 3, 4, 5, 6, 7, 8).

Você pode corresponder números com padrões como:

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

Mas você pode ver facilmente que não é a ferramenta certa.

O caractere [...] corresponde a um na lista de caracteres especificados, portanto, [121-300] corresponde a qualquer caractere que seja 1, 2, 1 a 3, 0 ou 0, por isso é o igual a [0-3] ou [0123] .

Uso:

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

Outra maneira de usar case seria como:

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

Ou use o operador ternário ( 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...

Ou, como @mikeserv, pense fora da caixa, inverta a lógica case e corresponda 1 ao valor dessas aritméticas comparações .

    
por 19.02.2013 / 12:36
4

Na verdade, isso é realmente fácil de fazer. A coisa sobre case é que ele sempre será expandido apenas o necessário para encontrar a primeira correspondência em relação a um padrão. Esse é o comportamento específico. E assim você pode apenas configurá-lo com uma string conhecida e avaliar as expansões dos padrões.

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 nunca expandirá mais desses padrões do que o necessário para encontrar um líder 1 no padrão. Isso é especialmente importante ao trabalhar com entrada do usuário, porque significa que você pode verificar com segurança o conteúdo de $number antes de tentar colocá-lo em um contexto de expansão aritmética na mesma declaração de caso em que você realmente o coloca em uma expansão matemática .

    
por 29.10.2015 / 11:09
1

Isso não é muito bom, mas você pode usar isso:

 #!/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
    
por 19.02.2013 / 12:36