Trocar caso com avanço?

193

Estou procurando a sintaxe correta da instrução switch com casos de queda no Bash (idealmente sem distinção entre maiúsculas e minúsculas). No PHP eu programava como:

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

Eu quero o mesmo no Bash:

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

De alguma forma, isso não funciona: a função do_what_you_are_supposed_to_do()deve ser acionada quando $ C for 2 OU 3.

Mischka
fonte
4
Não use funções de chamada com parênteses !!! Como você pode definir uma função no bash usando function fname { echo "Inside fname"; return 0; }ou fname() { echo "inside fname"; return 0; }colocando parens em uma chamada de função, pode parecer uma definição de função. Funções devem ser chamadas como qualquer outro programa de linha de comando, como mv, cp, rsync, ls, cd, etc ... Neste caso nós chamamos fname assim: fname $ARGS.
Charles Addis
do_nothing()deve ser uma declaração SKIP? Use :.
SJul

Respostas:

309

Use uma barra vertical ( |) para "ou".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac
geekosaur
fonte
30
Ou neste caso simples de uma classe de personagem[23])
SiegeX
4
@ Mischka - Observo que você não aceitou esta resposta, é porque ela não responde à parte inovadora da pergunta? A lógica de avanço é útil onde o processamento especial deve ocorrer antes do_what_you_are_supposed_to_do(), recolher o "2" e o "3" em um único caso não soluciona isso. Não tenho certeza se a edição da pergunta para esclarecer isso é razoável, pois é óbvio que muitas pessoas acharam esta resposta útil.
Tyson
1
@Tyson O OP não aceitou a resposta, pois é um usuário não registrado. Quanto à lógica "fall-through", como normalmente entendida pelos programadores, o corpo da pergunta demonstra um colapso da condição, não a lógica de fall-through. (Observe o uso breakno código php.) Editar a questão, ou seu título, nesta data invalidaria muitas das respostas que não fornecem queda-through lógica, e provavelmente não deve ser feito. Fall-through não estava no título até várias edições de outros usuários, mas é tarde demais para retirá-lo agora.
user7412956
100

bashVersões recentes permitem falhas usando ;&em vez de ;;: elas também permitem retomar as verificações de casos usando ;;&lá.

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

saída de amostra

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four
Jasen
fonte
1
Essa lógica neste exemplo foi difícil de seguir. Além disso, não acho que este exemplo realmente demonstre a diferença entre ;&e ;;&. Eu mudei o "24"para ;;& # resumee obtive os mesmos resultados, então ainda estou me perguntando quando você usaria o ;&avanço.
wisbucky
1
é um exemplo simples para uma coisa complexa - mudei ?4para [13]4torná-lo mais óbvio e para tornar sua alteração uma alteração
ininterrupta
26
  • Não use () nomes de funções por trás no bash, a menos que você queira defini-los.
  • use [23]no caso de combinar 2ou3
  • casos de string estáticos devem ser colocados em ''vez de""

Se incluído "", o intérprete (desnecessariamente) tenta expandir possíveis variáveis ​​no valor antes da correspondência.

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

Para correspondência sem distinção entre maiúsculas e minúsculas, você pode usar classes de caracteres (como [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

Mas abra não atingiu a qualquer momento, porque será correspondido pelo primeiro caso.

Se necessário, você pode omitir ;;no primeiro caso para continuar testando as correspondências nos seguintes casos também. ( ;;pula para esac)

Sprinterfreak
fonte
Você também pode converter C para minúsculas case "${C,,}" inse o caso não é importante
Sprinterfreak
1
O que acontece se você omitir o ;;? Você não deveria usar ;&para o avanço?
HelloGoodbye 22/01
1
Eu recebo um erro de sintaxe se omitir ;; , preciso usar ;;&se quiser continuar o teste.
Jasen
do_wild_mysterious_thingsfiz o meu dia
Julien__ 17/10/19
14

Tente o seguinte:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac
René Steetskamp
fonte
1
essa é uma dica muito útil. Pelo menos para o Bash 4.3.11. Eu não me incomodei em experimentá-lo em nenhum outro.
Daniel
3
Nota: Isso não funciona no bash 3.2, que ainda é o bash padrão no macOS.
Danny Kirchmeier
13

Se os valores forem inteiros, você poderá usar [2-3]ou poderá usar [5,7,8]valores não contínuos.

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

Se os valores forem string, você poderá usar |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done
rashok
fonte
para que serve shifto final?
Milkncookiez
1
shiftremove o primeiro argumento na lista de argumentos da CLI. Basicamente, em cada iteração desse loop, sempre $1é usado para obter cada argumento da lista de argumentos da CLI com a ajuda de shift.
rashok