¿Cambiar caso con fallthrough?

193

Estoy buscando la sintaxis correcta de la instrucción switch con casos fallidos en Bash (idealmente no distingue entre mayúsculas y minúsculas). En PHP lo programaría como:

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

Quiero lo mismo en Bash:

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

Esto de alguna manera no funciona: la función do_what_you_are_supposed_to_do()debe activarse cuando $ C es 2 O 3.

Mischka
fuente
44
¡No use las funciones de llamada con parens! Dado que puede definir una función en bash usando cualquiera function fname { echo "Inside fname"; return 0; }o fname() { echo "inside fname"; return 0; }colocando parens en una llamada de función, puede parecer que es una definición de función. Funciones deben ser llamadas como cualquier otro programa de línea de comandos como mv, cp, rsync, ls, cd, etc ... En este caso llamamos fnombre este modo: fname $ARGS.
Charles Addis
do_nothing()será una declaración SKIP? Uso :.
sjas

Respuestas:

309

Use una barra vertical ( |) para "o".

case "$C" in
"1")
    do_this()
    ;;
"2" | "3")
    do_what_you_are_supposed_to_do()
    ;;
*)
    do_nothing()
    ;;
esac
geekosaur
fuente
30
O en este caso simple de una clase de caracteres[23])
SiegeX
44
@Mischka - Noto que no has aceptado esta respuesta, ¿es porque no responde a la parte de la pregunta? La lógica de caída es útil cuando se debe realizar un procesamiento especial antes do_what_you_are_supposed_to_do(), al colapsar "2" y "3" en un solo caso no resuelve esto. No estoy seguro si editar la pregunta para aclarar esto es razonable, ya que es obvio que muchas personas han encontrado útil esta respuesta.
Tyson
1
@Tyson El OP no ha aceptado la respuesta, ya que es un usuario no registrado. En cuanto a la lógica de "caída", como la entienden normalmente los programadores, el cuerpo de la pregunta demuestra un colapso de la condición, no una lógica de caída. (Observe el uso de breaken el código php.) Edición de la cuestión, o su título, en esta fecha invalida muchas de las respuestas, que no proporcionan la caída a través de la lógica, y probablemente no se debe hacer. Fall-through no estaba en el título hasta varias ediciones de otros usuarios, pero es demasiado tarde para volver a sacarlo ahora.
user7412956
100

Las bashversiones recientes permiten el uso ;&fallido en lugar de ;;: también permiten reanudar las verificaciones de casos al usar ;;&allí.

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

salida de muestra

4 = four
14 = fourteen
24 = twenty-four
34 = thirty-four
Jasen
fuente
1
Esta lógica en este ejemplo fue difícil de seguir. Además, no creo que este ejemplo realmente demuestre la diferencia entre ;&y ;;&. Cambié "24"a ;;& # resumey obtuve los mismos resultados, por lo que todavía me pregunto cuándo ;&usarías la falla.
Wisbucky
1
es un ejemplo simple para algo complejo: cambié ?4a [13]4para hacerlo más obvio y para hacer que tu cambio sea un cambio radical
Jasen
26
  • No use ()nombres de funciones detrás de bash a menos que desee definirlos.
  • utilizar [23]en caso de que coincida 2o3
  • los casos de cadenas estáticas deben encerrarse en ''lugar de""

Si se incluye "", el intérprete (innecesariamente) intenta expandir las posibles variables en el valor antes de hacer coincidir.

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

Para la coincidencia entre mayúsculas y minúsculas, puede usar clases 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

Pero abrano golpeó en ningún momento porque será igualado por el primer caso.

Si es necesario, puede omitir ;;en el primer caso para continuar probando coincidencias en los siguientes casos también. ( ;;salta a esac)

Sprinterfreak
fuente
También puede convertir C a minúsculas case "${C,,}" insi el caso no es importante
Sprinterfreak
1
¿Qué sucede si omites el ;;? ¿No se supone que debes usar ;&para fallthrough?
HelloGoodbye
1
Recibo un error de sintaxis si omito ;; , necesito usarlo ;;&si deseo continuar probando.
Jasen
do_wild_mysterious_thingsme
alegró el
14

Prueba esto:

case $VAR in
normal)
    echo "This doesn't do fallthrough"
    ;;
special)
    echo -n "This does "
    ;&
fallthrough)
    echo "fall-through"
    ;;
esac
René Steetskamp
fuente
1
Ese es un consejo muy útil. Al menos para Bash 4.3.11. No me he molestado en probarlo en ningún otro.
Daniel
3
Nota: Esto no funciona para bash 3.2, que sigue siendo el bash predeterminado en macOS.
Danny Kirchmeier
13

Si los valores son enteros, puede usarlos [2-3]o puede usarlos [5,7,8]para valores no continuos.

#!/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 los valores son cadenas, puede usarlos |.

#!/bin/bash
while [ $# -gt 0 ];
do
    case $1 in
    "one")
        echo "one"
        ;;
    "two" | "three")
        echo "two or three"
        ;;
    *)
        echo "others"
        ;;
    esac
    shift
done
rashok
fuente
¿Para qué es el shiftfinal?
Milkncookiez
1
shiftelimina el primer argumento en la lista de argumentos de CLI. Básicamente, en cada iteración de este ciclo siempre $1se usa para obtener cada argumento de la lista de argumentos de CLI con la ayuda de shift.
rashok