Переключить случай с падением?

193

Я ищу правильный синтаксис оператора switch с падающими падежами в 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.

Mischka
источник
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
geekosaur
источник
31
Или в этом простом случае класс персонажей[23])
SiegeX
4
@Mischka - я отмечаю, что вы не приняли этот ответ, потому что он не отвечает на первую часть вопроса? Логика Fallthrough полезна в тех случаях, когда раньше должна происходить специальная обработка, поскольку объединение do_what_you_are_supposed_to_do()«2» и «3» в один случай не решает эту проблему. Я не уверен, разумно ли редактировать вопрос, чтобы сделать его более понятным, поскольку очевидно, что многие нашли этот ответ полезным.
Тайсон
1
@Tyson ОП не принял ответ, так как он является незарегистрированным пользователем. Что касается логики «провала», как это обычно понимают программисты, тело вопроса демонстрирует сворачивание условия, а не логики провала. (Обратите внимание на использовании breakв коде PHP.) Редактирование вопроса или его названия, на этой дате исправит многие ответы , которые действительно обеспечивают падение сквозной логики, и , вероятно , не должно быть сделано. Происшествия не было в названии до нескольких правок других пользователей, но уже слишком поздно, чтобы вернуть его обратно.
user7412956
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
Jasen
источник
1
Этой логике в этом примере было трудно следовать. Кроме того, я не думаю, что этот пример действительно демонстрирует разницу между ;&и ;;&. Я изменил "24"к ;;& # resumeи получил те же результаты, так что я до сих пор интересно , когда вы будете использовать ;&проваливаемся.
Висбуки
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)

Sprinterfreak
источник
Вы также можете преобразовать C в строчные, case "${C,,}" inесли регистр не важен
Sprinterfreak
1
Что произойдет, если вы пропустите ;;? Разве вы не должны использовать ;&для падения?
Здравствуйте, до свидания
1
Я получаю синтаксическую ошибку, если я ее опускаю, ;; мне нужно использовать, ;;&если я хочу продолжить тестирование.
Jasen
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
это очень полезный совет. По крайней мере, для Bash 4.3.11. Я не удосужился попробовать это на любых других.
Даниэль
3
Примечание: это не работает для bash 3.2, который по-прежнему является bash по умолчанию в macOS.
Дэнни Кирхмайер
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
rashok
источник
для чего shiftв конце?
Milkncookiez
1
shiftудаляет первый аргумент в списке аргументов CLI. В основном на каждой итерации этого цикла всегда $1используется для получения каждого аргумента из списка аргументов CLI с помощью shift.
рашок