case + як реалізувати рівний чи менший або більший у синтаксисі case


9

Моя мета - перевірити діапазон числа за допомогою (лише за допомогою case+ esac) та надрукувати діапазон. Так, наприклад:

  • Якщо число від 0 до 80, надрукуйте >=0<=80
  • Якщо число становить від 81 до 100, друкуйте >=81<=100
  • тощо.

Проблема з моїм сценарієм нижче друкується лише в тому >=0<=90випадку, якщо число між 0 і 9. Як виправити мій сценарій, щоб він надрукував правильний вихід відповідно до діапазону чисел?

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

Відповіді:


6

caseтільки для зіставлення з зразком, він не буде виконувати арифметичні обчислення ( за винятком , може бути , якщо ви вважаєте zsh«s <x-y>розширений оператор зіставлення з зразком). Потрібно [...]лише відповідати одному символу (або збірному елементу в деяких реалізаціях) на основі набору, визначеного всередині. Так, наприклад , [0-80]буде відповідати один символ , якщо це один з 0до 8або 0(тобто, один з 0, 1, 2, 3, 4, 5, 6, 7, 8).

Ви можете зіставити числа за допомогою таких моделей:

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

Але ви легко бачите, що це не правильний інструмент.

[...]Відповідає один символ проти списку заданих символів, так [121-300]сірників для будь-якого символу, або 1, 2, 1 до 3, 0 або 0, так що це так само , як [0-3]і [0123].

Використання:

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

Іншим способом використання caseбуде такий:

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

Або скористайтеся потрійним оператором ( 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...

Або як @mikeserv, мислити нестандартно, звернути caseлогіку і відповідність 1із значенням цих арифметичних порівнянь .


1
+1, врахуйте if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else. Менше вводити, менше схильних до помилок.
петерф

@peterph Також потрібно тривати більше часу.
Кен Шарп

4

Насправді це зробити дуже просто. Справа в тому case, що вона завжди буде розширюватися лише стільки, скільки потрібно, щоб знайти першу відповідність схемі. Це специфіка поведінки. Отже, ви можете просто встановити його за допомогою відомого рядка та оцінити розширення шаблонів.

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ніколи більше не буде розширювати ці шаблони, ніж це потрібно для того, щоб знайти провідну 1 у шаблоні. Це особливо важливо під час роботи з введенням користувача, оскільки це означає, що ви можете безпечно перевірити вміст, $numberперш ніж намагатися помістити його в контекст арифметичного розширення в тому самому операторі, в якому ви насправді ставите його в математичне розширення.


👍 Мені подобається те, як ти думаєш поза / навколо коробки.
Стефан Шазелас

@ StéphaneChazelas - мені подобається case. є кілька цікавих речей, які ви можете зробити з $((математикою, ))і case- особливо навколишні завдання в шаблонах, які ніколи не трапляться, поки вони не стануть необхідними, - і ви навіть можете створити дерева розбору, які розширять вкладені рекурсії, якщо ви заселите візерунки aliasланцюжком. найшвидший спосіб, коли я знайшов оболонку, щоб робити такі речі, як переклад символів, і поміняти символи на значення байтів. це може бути досить швидко - C-Locale ASCII + <> восьмеричний найгірший випадок - це 7 базових розширень візерунка POSIX.
mikeserv

1

Це не дуже приємно, але ви можете використовувати це:

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

Ви можете захотіти "канонізувати" число за допомогою $ (($ число)), щоб прикрити такі цифри, як "001" або "0x99" ... Це також охоплюватиме "12" і "12 + 12", які можуть або можуть не бажати.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.