Gehäuse mit Durchfall wechseln?

193

Ich suche nach der richtigen Syntax der switch-Anweisung mit Fallthrough-Fällen in Bash (idealerweise ohne Berücksichtigung der Groß- und Kleinschreibung). In PHP würde ich es wie folgt programmieren:

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

Ich möchte dasselbe in Bash:

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

Das funktioniert irgendwie nicht: Die Funktion do_what_you_are_supposed_to_do()sollte ausgelöst werden, wenn $ C 2 ODER 3 ist.

Mischka
quelle
4
Verwenden Sie keine Anruffunktionen mit Parens !!! Da Sie eine Funktion in Bash definieren können, indem Sie entweder einen function fname { echo "Inside fname"; return 0; }oder einen fname() { echo "inside fname"; return 0; }Parens für einen Funktionsaufruf verwenden, kann dies so aussehen, als wäre es eine Funktionsdefinition. Funktionen sind wie alle anderen Kommandozeilen - Programm wie genannt werden mv, cp, rsync, ls, cd, etc ... In diesem Fall sind wir fname gerne so nennen: fname $ARGS.
Charles Addis
do_nothing()soll eine SKIP-Erklärung sein? Verwenden Sie :.
Sjas

Antworten:

309

Verwenden Sie einen vertikalen Balken ( |) für "oder".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac
Geekosaurier
quelle
30
Oder in diesem einfachen Fall eine Charakterklasse[23])
SiegeX
4
@Mischka - Ich stelle fest, dass Sie diese Antwort nicht akzeptiert haben. Ist das so, weil sie den Fallthrough-Teil der Frage nicht beantwortet? Fallthrough-Logik ist nützlich, wenn zuvor eine spezielle Verarbeitung erfolgen sollte. Wenn Sie do_what_you_are_supposed_to_do()sowohl "2" als auch "3" in einem einzigen Fall zusammenfassen, wird dies nicht behoben . Ich bin mir nicht sicher, ob es sinnvoll ist, die Frage zu bearbeiten, um dies klarer zu machen, da es offensichtlich ist, dass viele Leute diese Antwort hilfreich fanden.
Tyson
1
@Tyson Das OP hat die Antwort nicht akzeptiert, da es sich um einen nicht registrierten Benutzer handelt. In Bezug auf die "Durchfall" -Logik, wie sie normalerweise von Programmierern verstanden wird, zeigt der Fragetext einen Zusammenbruch des Zustands, nicht eine Durchfalllogik . (Beachten Sie die Verwendung von breakin der PHP - Code.) Bearbeiten der Frage, oder der Titel, zu diesem Zeitpunkt viele Antworten ungültig machen würde , die keine Durchfall Logik zur Verfügung stellen, und wahrscheinlich nicht getan werden sollte. Fall-through war erst nach mehreren Änderungen durch andere Benutzer im Titel enthalten, aber es ist zu spät, um es jetzt wieder herauszunehmen.
user7412956
100

Neuere bashVersionen ermöglichen das Durchfallen durch Verwendung ;&von anstelle von ;;: Sie ermöglichen auch die Wiederaufnahme der Fallprüfungen, indem sie ;;&dort verwendet werden.

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

Beispielausgabe

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four
Jasen
quelle
1
Diese Logik in diesem Beispiel war schwer zu befolgen. Ich glaube auch nicht, dass dieses Beispiel den Unterschied zwischen ;&und wirklich zeigt ;;&. Ich änderte die "24"an ;;& # resumeund bekam die gleichen Ergebnisse, so frage ich mich immer noch , wenn Sie verwenden würden ;&fallthrough.
wisbucky
1
Es ist ein einfaches Beispiel für eine komplexe Sache - ich habe mich geändert ?4, [13]4um es offensichtlicher zu machen und um Ihre Änderung zu einer bahnbrechenden Änderung zu machen
Jasen
26
  • Verwenden ()Sie in bash keine Funktionsnamen hinter, es sei denn, Sie möchten sie definieren.
  • Verwenden Sie [23]für den Fall, dass 2oder3
  • statische Zeichenfolgen sollten von ''statt eingeschlossen werden""

Wenn eingeschlossen "", versucht der Interpreter (unnötig), mögliche Variablen im Wert vor dem Abgleich zu erweitern.

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

Für Übereinstimmungen ohne Berücksichtigung der Groß- und Kleinschreibung können Sie Zeichenklassen (wie [23]) verwenden:

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

Hat abraaber zu keinem Zeitpunkt getroffen, da es vom ersten Fall abgeglichen wird.

Bei Bedarf können Sie ;;im ersten Fall weglassen, um auch in den folgenden Fällen nach Übereinstimmungen zu suchen. ( ;;springt zu esac)

Sprinterfreak
quelle
Sie können C auch in Kleinbuchstaben umwandeln, case "${C,,}" inwenn die Groß- / Kleinschreibung nicht wichtig ist
Sprinterfreak
1
Was passiert, wenn Sie das weglassen ;;? ;&Solltest du nicht zum Durchfallen verwenden?
HelloGoodbye
1
Ich erhalte einen Syntaxfehler, wenn ich weglasse, dass ;; ich ihn verwenden muss, ;;&wenn ich weiter testen möchte.
Jasen
do_wild_mysterious_thingsmachte meinen Tag
Julien__
14

Versuche dies:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac
René Steetskamp
quelle
1
Das ist ein sehr hilfreicher Tipp. Zumindest für Bash 4.3.11. Ich habe mich nicht darum gekümmert, es an anderen zu versuchen.
Daniel
3
Hinweis: Dies funktioniert nicht für Bash 3.2, das in macOS immer noch das Standard-Bash ist.
Danny Kirchmeier
13

Wenn die Werte ganzzahlig sind, können Sie sie verwenden [2-3]oder [5,7,8]für nicht kontinuierliche Werte verwenden.

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

Wenn die Werte Zeichenfolge sind, können Sie verwenden |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done
Rashok
quelle
Wofür ist das shiftam Ende?
Milkncookiez
1
shiftEntfernt das erste Argument in der Liste der CLI-Argumente. Grundsätzlich wird bei jeder Iteration dieser Schleife immer $1verwendet, um jedes Argument mit Hilfe von aus der CLI-Argumentliste abzurufen shift.
Rashok