Zamienić skrzynkę z przewrotem?


193

Szukam poprawnej składni instrukcji switch z przypadkowymi przypadkami w języku Bash (najlepiej bez rozróżniania wielkości liter). W PHP programowałbym to tak:

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

Chcę to samo w Bash:

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

To jakoś nie działa: funkcja do_what_you_are_supposed_to_do()powinna zostać uruchomiona, gdy $ C wynosi 2 LUB 3.


4
Nie używaj funkcji połączeń z parens !!! Ponieważ można zdefiniować funkcję w bashu za pomocą jednego z nich function fname { echo "Inside fname"; return 0; }lub fname() { echo "inside fname"; return 0; }umieszczenia parens w wywołaniu funkcji, może to wyglądać na definicję funkcji. Funkcje powinny być nazywane jak każdy inny program wiersza poleceń, takich jak mv, cp, rsync, ls, cd, etc ... W tym przypadku nazywamy fname tak: fname $ARGS.
Charles Addis,

do_nothing()będzie oświadczenie SKIP? Zastosowanie :.
sjas,

Odpowiedzi:


309

Użyj pionowego paska ( |) dla „lub”.

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

30
Lub w tym prostym przypadku klasa postaci[23])
SiegeX

4
@Mischka - Zauważyłem, że nie zaakceptowałeś tej odpowiedzi, czy to dlatego, że nie odpowiada na przełomową część pytania? Logika rewolucyjna jest przydatna tam, gdzie wcześniej powinno nastąpić specjalne przetwarzanie do_what_you_are_supposed_to_do(), zwijanie zarówno „2”, jak i „3” w jedną sprawę nie rozwiązuje tego problemu. Nie jestem pewien, czy edytowanie pytania w celu wyjaśnienia jest uzasadnione, ponieważ oczywiste jest, że wiele osób uznało tę odpowiedź za pomocną.
Tyson

1
@Tyson OP nie zaakceptował odpowiedzi, ponieważ jest niezarejestrowanym użytkownikiem. Jeśli chodzi o logikę „przelotową”, jak zwykle rozumieją to programiści, treść pytania pokazuje załamanie się stanu, a nie logikę upadkową. (Zawiadomienie użycie breakw kodzie PHP.) Montaż na pytanie, czy jego tytuł, w tym dniu będzie unieważnić wielu odpowiedzi, które nie przewidują spadek-poprzez logikę i chyba nie powinno być zrobione. Fall-through nie pojawił się w tytule aż do kilku edycji dokonanych przez innych użytkowników, ale jest już za późno, aby go wycofać.
user7412956

100

Najnowsze bashwersje pozwalają ;&na awarię, używając zamiast ;;: umożliwiają także wznowienie sprawdzania spraw przy użyciu ;;&tam.

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

próbka wyjściowa

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

1
Ta logika w tym przykładzie była trudna do przestrzegania. Ponadto nie sądzę, aby ten przykład naprawdę pokazuje różnicę między ;&i ;;&. Zmieniłem "24"się ;;& # resumei dostał takie same wyniki, więc wciąż zastanawiam się, kiedy należy użyć ;&fallthrough.
wisbucky

1
to prosty przykład złożonej rzeczy - zmieniłem, ?4aby [13]4uczynić to bardziej oczywistym, i aby twoja zmiana była przełomową zmianą
Jasen

26
  • Nie używaj ()nazw funkcji za bash, chyba że chcesz je zdefiniować.
  • użyj [23]w przypadku dopasowania 2lub3
  • statyczne ciągi znaków powinny być ujęte w ''miejsce zamiast""

Jeśli jest włączony "", interpreter (niepotrzebnie) próbuje rozszerzyć możliwe zmienne w wartości przed dopasowaniem.

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

W przypadku dopasowywania bez rozróżniania wielkości liter można użyć klas znaków (takich jak [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

Ale abranigdy nie trafił, ponieważ będzie pasował do pierwszego przypadku.

W razie potrzeby możesz pominąć ;;w pierwszym przypadku, aby kontynuować testowanie dopasowań również w następujących przypadkach. ( ;;skacze do esac)


Możesz także przekonwertować C na małe litery, case "${C,,}" injeśli sprawa nie jest ważna
Sprinterfreak

1
Co się stanie, jeśli pominiesz ;;? Nie powinieneś używać ;&do przewrotu?
HelloGoodbye

1
Dostaję błąd składniowy, jeśli pominę ;; , muszę użyć, ;;&jeśli chcę kontynuować testowanie.
Jasen

do_wild_mysterious_thingszrobiłem mój dzień
Julien__

14

Spróbuj tego:

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

1
to bardzo pomocna wskazówka. Przynajmniej dla Bash 4.3.11. Nie zadałem sobie trudu, aby wypróbować to na innych.
Daniel

3
Uwaga: Nie działa to w przypadku wersji bash 3.2, która nadal jest domyślną wersją bash w systemie macOS.
Danny Kirchmeier

13

Jeśli wartości są liczbami całkowitymi, możesz użyć [2-3]lub możesz użyć [5,7,8]dla wartości nieciągłych.

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

Jeśli wartości są ciągiem, możesz użyć |.

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

po co jest shiftkoniec?
Milkncookiez

1
shiftusuwa pierwszy argument z listy argumentów CLI. Zasadniczo przy każdej iteracji tej pętli zawsze $1używa się każdego argumentu z listy argumentów CLI shift.
rashok
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.