case + come implementare uguale o minore o maggiore nella sintassi case


9

Il mio obiettivo è verificare un intervallo di numeri con (solo con case+ esac) e stampare l'intervallo. Quindi per esempio:

  • Se il numero è compreso tra 0 e 80, stampare >=0<=80
  • Se il numero è compreso tra 81 e 100, stampare >=81<=100
  • eccetera.

Il problema con il mio script di seguito viene stampato solo >=0<=90se il numero è compreso tra 0 e 9. Come correggere il mio script, in modo che stamperà l'output corretto in base all'intervallo numerico?

#!/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

Risposte:


6

caseè solo per la corrispondenza dei modelli, non eseguirà una valutazione aritmetica (tranne forse se si considera zshl' <x-y>operatore di corrispondenza dei modelli estesa). Deve [...]solo abbinare un carattere (o elemento di confronto in alcune implementazioni) in base all'insieme specificato all'interno. Così, per esempio, [0-80]potrebbe corrispondere a un carattere se è uno 0di 8o 0(cioè, uno di 0, 1, 2, 3, 4, 5, 6, 7, 8).

Puoi abbinare i numeri a modelli come:

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

Ma puoi facilmente vedere che non è lo strumento giusto.

L' [...]corrisponde un personaggio con l'elenco dei caratteri specificati, quindi [121-300]partite per qualsiasi carattere che è o 1, 2, 1-3, 0 o 0, quindi è lo stesso come [0-3]o [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

Un altro modo di usare casesarebbe come:

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

Oppure usa l'operatore ternario ( 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...

O come @mikeserv, pensa fuori dagli schemi, inverti la caselogica e combacia 1con il valore di quei confronti aritmetici .


1
+1, considera if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else. Meno battitura a macchina, meno soggetto a errori.
peterph,

@peterph Ci vuole anche più tempo per l'esecuzione.
Ken Sharp,

4

In realtà questo è davvero facile da fare. Il fatto caseè che si espanderà sempre solo quanto è necessario per trovare la prima corrispondenza contro uno schema. Questo è un comportamento specifico. E così puoi semplicemente configurarlo con una stringa nota e valutare le espansioni dei modelli.

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

casenon espanderà mai più di quei modelli di quanto non sia necessario per trovare un 1 iniziale nel modello. Ciò è particolarmente importante quando si lavora con l'input dell'utente, perché significa che è possibile verificare in sicurezza il contenuto di $numberprima di aver mai provato a inserirlo in un contesto di espansione aritmetica nella stessa istruzione case in cui lo si inserisce effettivamente in un'espansione matematica.


👍 Mi piace il modo in cui pensi all'esterno / intorno alla scatola.
Stéphane Chazelas,

@ StéphaneChazelas - mi piace case. ci sono alcune cose interessanti che puoi fare con la $((matematica ))e case- specialmente le assegnazioni circostanti in schemi che non accadono mai fino a quando non sono necessarie - e puoi persino costruire alberi di analisi che espandono le ricorsioni annidate se popoli i motivi con una aliascatena. è il modo più veloce che ho trovato per ottenere una shell per fare cose come la traduzione di caratteri e scambiare caratteri con valori di byte. può essere piuttosto veloce - il caso peggiore in C-Locale ASCII + <> ottale è 7 espansioni di pattern POSIX di base.
Mikeserv,

1

Questo non è molto carino ma puoi usarlo:

 #!/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

Potresti voler "canonificare" il numero con $ (($ number)) per coprire numeri come "001" o "0x99" ... Questo coprirebbe anche per "12" e "12 + 12" che possono o possono non essere desiderabile.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.