Les instructions bash case peuvent-elles se mettre en cascade?

29

J'essaie de faire quelque chose comme ça:

case $level in
    3)
        echo "Level Three"

    2)
        echo "Level Two"

    1)
        echo "Level one"
        ;;
esac

où si $ level = 3, il produirait

Level Three
Level Two
Level One

tandis que si $ level = 1, il ne produirait que

Level One

Mais quand je l'essaye, j'obtiens l'erreur syntax error near unexpected token ')'parce que je n'ai pas inclus le ;;.

Toutes les autres langues que je connais le permettent, existe-t-il un moyen de le faire en bash? Une sorte de mot clé qui signifie "maintenant, continuez et faites le prochain cas comme s'il correspondait"?

Benubird
la source
2
Si chaque langue que vous connaissez le permet, vous devez apprendre des langues autres que C et ses imitateurs. Fallthrough dans les déclarations de cas est un accident de conception historique en C qui a survécu en quelque sorte dans des langages plus fondés sur des principes.
Gilles 'SO- arrête d'être méchant'

Réponses:

42

Vous devez utiliser ;&au lieu de ;;pour obtenir un comportement de substitution :

#! /bin/bash
foo() {
    case "$1" in
        3)
            echo "Level Three"
            ;&
        2)
            echo "Level Two"
            ;&
        1)
            echo "Level One"
            ;;
        a)
            echo "Level a"
            ;&
        b)
            echo "Level b"
            ;&
        c)
            echo "Level c"
            ;;
    esac
}
echo 3:
foo 3
echo 2:
foo 2
echo a:
foo a
3:
Level Three
Level Two
Level one
2:
Level Two
Level one
a:
Level a
Level b
Level c

Voir la section Constructions conditionnelles de la documentation bash.

L'autre marqueur spécial est ;;&, qui:

oblige le shell à tester les modèles de la clause suivante, le cas échéant, et à exécuter toute liste de commandes associée sur une correspondance réussie.

;; est toujours final, aucun autre motif n'est testé.

#! /bin/bash

foo() {
    case "$1" in
        *3*)
            echo "Level Three"
            ;;&
        *2*)
            echo "Level Two"
            ;;&
        *1*)
            echo "Level One"
            ;;&
    esac
}

echo 12:
foo 12
echo 13:
foo 13
echo 23:
foo 23
12:
Level Two
Level One
13:
Level Three
Level One
23:
Level Three
Level Two
Tapis
la source
18
Remarque sur la portabilité: cette syntaxe n'est pas POSIX. Il provient kshet est disponible en ksh, bash(depuis 4.0, 2009) et zsh(depuis 3.1.2, 1997). ;;&est spécifique à bash.
Stéphane Chazelas
4
Notez également que l' zshéquivalent de bashl » ;;&est ;|(ajoutée en 4.3.3, 2007).
Stéphane Chazelas