Boîtier de commutation avec chute?

193

Je recherche la syntaxe correcte de l'instruction switch avec les cas de chute dans Bash (idéalement insensible à la casse). En PHP, je le programmerais comme:

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

Je veux la même chose dans Bash:

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

Cela ne fonctionne pas: la fonction do_what_you_are_supposed_to_do()doit être déclenchée lorsque $ C vaut 2 OU 3.

Mischka
la source
4
N'utilisez pas de fonctions d'appel avec des parenthèses !!! Puisque vous pouvez définir une fonction dans bash en utilisant l'un function fname { echo "Inside fname"; return 0; }ou l' autre ou en fname() { echo "inside fname"; return 0; }plaçant des parenthèses sur un appel de fonction, cela peut ressembler à une définition de fonction. Les fonctions doivent être appelées comme tout autre programme de ligne de commande tels que mv, cp, rsync, ls, cd, etc ... Dans ce cas , nous appelons FNAME comme ceci: fname $ARGS.
Charles Addis
do_nothing()doit être une déclaration SKIP? Utilisez :.
sjas le

Réponses:

309

Utilisez une barre verticale ( |) pour "ou".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac
geekosaure
la source
31
Ou dans ce cas simple, une classe de personnage[23])
SiegeX
4
@Mischka - Je note que vous n'avez pas accepté cette réponse, est-ce parce qu'elle ne répond pas à la partie de la question? La logique de repli est utile là où un traitement spécial doit avoir lieu avant do_what_you_are_supposed_to_do(), le regroupement de «2» et «3» en un seul cas ne résout pas ce problème. Je ne sais pas s'il est raisonnable de modifier la question pour clarifier les choses, car il est évident que de nombreuses personnes ont trouvé cette réponse utile.
Tyson
1
@Tyson L'OP n'a pas accepté la réponse, car il s'agit d'un utilisateur non enregistré. Quant à la logique «fall-through», telle qu'elle est normalement comprise par les programmeurs, le corps de la question démontre un effondrement de la condition et non une logique fall-through. (Notez l'utilisation breakdans le code php.) Modification de la question, ou son titre, à cette date invaliderait bon nombre des réponses qui ne fournissent retombées par la logique, et ne devrait probablement pas être fait. Fall-through n'était pas dans le titre avant plusieurs modifications par d'autres utilisateurs, mais il est trop tard pour le retirer maintenant.
user7412956
100

Les bashversions récentes permettent de passer par l'utilisation ;&au lieu de ;;: elles permettent également de reprendre les vérifications de cas en utilisant;;& 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

sortie d'échantillon

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four
Jasen
la source
1
Cette logique dans cet exemple était difficile à suivre. De plus, je ne pense pas que cet exemple démontre vraiment la différence entre ;&et ;;&. J'ai changé le "24"en ;;& # resumeet j'ai obtenu les mêmes résultats, donc je me demande toujours quand vous utiliseriez ;&fallthrough.
wisbucky
1
c'est un exemple simple pour une chose complexe - j'ai changé ?4pour [13]4le rendre plus évident, et pour faire de votre changement un changement radical
Jasen
26
  • N'utilisez pas ()derrière les noms de fonction dans bash sauf si vous souhaitez les définir.
  • utiliser [23]au cas où pour correspondre 2ou3
  • les cas de chaîne statique doivent être encadrés par '' au lieu de""

Si inclus dans "" , l'interpréteur essaie (inutilement) d'étendre les variables possibles dans la valeur avant la correspondance.

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

Pour une correspondance insensible à la casse, vous pouvez utiliser des classes de caractères (comme [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

Mais abran'a pas frappé à tout moment car il correspondra au premier cas.

Si nécessaire, vous pouvez omettre ;;dans le premier cas de continuer à tester les correspondances dans les cas suivants également. ( ;;saute à esac)

Sprinterfreak
la source
Vous pouvez également convertir C en minuscules case "${C,,}" insi la casse n'est pas importante
Sprinterfreak
1
Que se passe-t-il si vous omettez le ;;? N'êtes-vous pas censé utiliser ;&pour la chute?
HelloGoodbye le
1
J'obtiens une erreur de syntaxe si j'oublie que ;; je dois utiliser ;;&si je veux continuer le test.
Jasen
do_wild_mysterious_thingsfait ma journée
Julien__
14

Essaye ça:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac
René Steetskamp
la source
1
c'est une astuce très utile. Au moins pour Bash 4.3.11. Je n'ai pas pris la peine de l'essayer sur d'autres.
Daniel
3
Remarque: cela ne fonctionne pas pour bash 3.2, qui est toujours le bash par défaut dans macOS.
Danny Kirchmeier
13

Si les valeurs sont des nombres entiers, vous pouvez utiliser [2-3]ou vous pouvez utiliser [5,7,8]pour des valeurs non continues.

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

Si les valeurs sont des chaînes, vous pouvez utiliser |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done
rashok
la source
à quoi sert la shiftfin?
Milkncookiez
1
shiftsupprime le premier argument de la liste des arguments CLI. Fondamentalement, à chaque itération de cette boucle, $1on utilise toujours pour obtenir chaque argument de la liste d'arguments CLI à l'aide de shift.
rashok