Перемикайте корпус з падінням?


193

Я шукаю правильний синтаксис оператора перемикання з випадаючими випадками в Bash (в ідеалі не залежно від регістру). У PHP я програмував би це так:

switch($c) {
    case 1:
        do_this();
        break;
     case 2:
     case 3:
        do_what_you_are_supposed_to_do();
        break;
     default:
        do_nothing(); 
}

Я хочу те ж саме в Bash:

case "$C" in
    "1")
        do_this()
        ;;
    "2")
    "3")
        do_what_you_are_supposed_to_do()
        ;;
    *)
        do_nothing();
        ;; 
esac

Це якось не працює: функцію do_what_you_are_supposed_to_do()слід запускати, коли $ C становить 2 АБО 3.


4
Не використовуйте функції виклику з паролями !!! Оскільки ви можете визначити функцію в bash, використовуючи function fname { echo "Inside fname"; return 0; }або fname() { echo "inside fname"; return 0; }встановлення паролів на виклик функції, може виглядати як визначення функції. Функції повинні називатися як і будь-який інший програми командного рядка , такі як mv, cp, rsync, ls, cdі т.д. ... У цьому випадку ми називаємо Fname подобається так: fname $ARGS.
Чарльз Аддіс

do_nothing()повинна бути заявою SKIP? Використовуйте :.
sjas

Відповіді:


309

Використовуйте вертикальну смугу ( |) для "або".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac

30
Або в цьому простому випадку клас персонажів[23])
SiegeX

4
@Mischka - Зауважу, ви не прийняли цю відповідь, це тому, що вона не відповідає детальній частині питання? Логіка поглиблення корисна там, де раніше повинна відбуватися спеціальна обробка do_what_you_are_supposed_to_do(), згортаючи і "2", і "3" в один випадок, це не вдається вирішити. Я не впевнений, якщо редагування питання зробити це ясніше розумним, оскільки очевидно, що багато людей вважають цю відповідь корисною.
Тайсон

1
@Tyson ОП не прийняв відповідь, оскільки це незареєстрований користувач. Щодо логіки "пропускання", як це зазвичай розуміють програмісти, орган запитання демонструє руйнування умови, а не логіку пропускання. (Зверніть увагу на використанні breakв коді PHP.) Редагування питання або його назви, на цій даті виправить багато відповідей , які дійсно забезпечують падіння наскрізний логіки, і , ймовірно , не повинно бути зроблено. Проголошення не було в заголовку до кількох редагувань інших користувачів, але вже пізно, щоб повернути його назад.
користувач7412956

100

Останні bashверсії дозволяють пропускати, використовуючи ;&замість них ;;: вони також дозволяють відновити перевірку справ, використовуючи ;;&там.

for n in 4 14 24 34
do
  echo -n "$n = "
  case "$n" in
   3? )
     echo -n thirty-
     ;;&   #resume (to find ?4 later )
   "24" )
     echo -n twenty-
     ;&   #fallthru
   "4" | [13]4)
     echo -n four 
     ;;&  # resume ( to find teen where needed )
   "14" )
     echo -n teen
  esac
  echo 
done

вибірка вибірки

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four

1
Цю логіку в цьому прикладі було важко дотримуватися. Крім того, я не думаю, що цей приклад насправді демонструє різницю між ;&та ;;&. Я змінив "24"на ;;& # resumeта отримав однакові результати, тому мені все ще цікаво, коли ви будете використовувати ;&падіння.
wisbucky

1
це простий приклад складної речі - я змінив, ?4щоб [13]4зробити це більш очевидним, і щоб ваша зміна стала переломною
Jasen

26
  • Не використовуйте ()імена функцій в bash, якщо ви не хочете їх визначати.
  • використовувати [23]у випадку, якщо відповідати 2або3
  • випадки статичного рядка повинні бути додані ''замість""

Якщо він укладений "", інтерпретатор (без потреби) намагається розширити можливі змінні значення перед узгодженням.

case "$C" in
'1')
    do_this
    ;;
[23])
    do_what_you_are_supposed_to_do
    ;;
*)
    do_nothing
    ;;
esac

Для нечутливої ​​відповідності регістру можна використовувати класи символів (наприклад [23]):

case "$C" in

# will match C='Abra' and C='abra'
[Aa]'bra')
    do_mysterious_things
    ;;

# will match all letter cases at any char like `abra`, `ABRA` or `AbRa`
[Aa][Bb][Rr][Aa])
    do_wild_mysterious_things
    ;;

esac

Але abraне потрапив ніколи, тому що це буде відповідати першому випадку.

Якщо потрібно, ;;у першому випадку ви можете пропустити тестування на відповідність і в наступних випадках. ( ;;стрибає на esac)


Ви також можете конвертувати C у малі регістри, case "${C,,}" inякщо справа не важлива
Sprinterfreak

1
Що станеться, якщо ви пропустите ;;? Хіба ви не повинні використовувати ;&для прориву?
HelloGoodbye

1
Я отримую помилку в синтаксисі, якщо пропускаю, що ;; мені потрібно використовувати, ;;&якщо хочу продовжити тестування.
Ясен

do_wild_mysterious_thingsзробив мій день
Julien__

14

Спробуйте це:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac

1
це дуже корисна порада. Принаймні для Баша 4.3.11. Я не намагався спробувати це на будь-яких інших.
Даніель

3
Примітка. Це не працює для bash 3.2, який все ще є bash за замовчуванням у macOS.
Danny Kirchmeier

13

Якщо значення цілі, тоді ви можете використовувати [2-3]або використовувати [5,7,8]для неперервних значень.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    1)
        echo "one"
        ;;
    [2-3])
        echo "two or three"
        ;;
    [4-6])
        echo "four to six"
        ;;
    [7,9])
        echo "seven or nine"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done

Якщо значення є рядковими, то ви можете використовувати |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done

для чого shiftв кінці?
Milkncookiez

1
shiftвидаляє перший аргумент із списку аргументів CLI. В основному для кожної ітерації цього циклу завжди $1використовується для отримання кожного аргументу зі списку аргументів CLI за допомогою shift.
рашок
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.