A instrução case é uma estrutura de controle condicional no Bash que permite executar diferentes blocos de código com base no valor de uma expressão. Diferente do if, que testa condições booleanas, o case compara a expressão com uma série de padrões (usando globs) e executa o primeiro que corresponder. É uma ferramenta poderosa para simplificar cadeias longas de if-elif-else, especialmente quando se lida com valores discretos ou padrões simples.

Nesta aula, veremos a sintaxe completa, como os padrões funcionam com curingas, a ausência de fall-through (ao contrário de linguagens como C), e os casos de uso mais comuns, incluindo processamento de argumentos de linha de comando e menus interativos.

Sintaxe

A sintaxe básica do case é:

case expressão in
    padrão1)
        comandos
        ;;
    padrão2)
        comandos
        ;;
    *)
        comandos
        ;;
esac

A expressão é avaliada e comparada com cada padrão na ordem em que aparecem. O primeiro padrão que corresponder faz com que os comandos associados sejam executados. O terminador ;; indica o fim do bloco de comandos para aquele padrão. O padrão *) é opcional e funciona como um curinga que corresponde a qualquer coisa, servindo como caso padrão (similar ao default em outras linguagens).

Exemplo simples:

#!/bin/bash
read -p "Digite uma letra: " letra
case $letra in
    a)
        echo "Você digitou a"
        ;;
    b)
        echo "Você digitou b"
        ;;
    *)
        echo "Você digitou outra letra"
        ;;
esac

Padrões (globs)

Os padrões no case são expressões glob (não são expressões regulares). Eles podem conter curingas como * (qualquer sequência), ? (um caractere qualquer), e classes de caracteres [abc] ou [a-z]. Também é possível usar múltiplos padrões separados por | para corresponder a várias opções.

Exemplo com curingas:

#!/bin/bash
read -p "Digite um caractere: " char
case $char in
    [a-z])
        echo "Letra minúscula"
        ;;
    [A-Z])
        echo "Letra maiúscula"
        ;;
    [0-9])
        echo "Dígito"
        ;;
    ?)
        echo "Outro caractere único"
        ;;
    *)
        echo "Sequência de caracteres"
        ;;
esac

Note que a ordem dos padrões importa: se você colocar *) antes, ele corresponderá a tudo e os outros nunca serão testados.

Fall-through

Ao contrário de linguagens como C, o Bash não possui fall-through automático. Cada bloco de comandos é terminado por ;; e o fluxo sai do case após a execução. Não há necessidade de break. Se você omitir o ;;, o Bash continuará executando os comandos do próximo padrão, mas isso é considerado um erro de sintaxe (o interpretador pode reclamar). Na prática, sempre use ;; para evitar comportamento inesperado.

Exemplo de fall-through acidental (erro):

#!/bin/bash
case "a" in
    a)
        echo "Primeiro"
        # sem ;;
    b)
        echo "Segundo"
        ;;
esac

Isso causará um erro de sintaxe porque o Bash espera ;; antes do próximo padrão. Para simular fall-through, você pode usar ;& (que continua testando o próximo padrão) ou ;;& (que continua executando o próximo bloco independentemente). Mas esses são recursos avançados e raramente usados.

Casos de uso

O case é ideal para situações onde uma variável pode assumir um conjunto limitado de valores. Exemplos comuns:

  • Processamento de argumentos de linha de comando (como em scripts que aceitam flags -v, -h, etc.)
  • Menus interativos (usuário escolhe uma opção)
  • Verificação de tipos de arquivo (extensão)
  • Tratamento de sinais ou códigos de retorno

Exemplo de processamento de argumentos:

#!/bin/bash
while [ $# -gt 0 ]; do
    case "$1" in
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -h|--help)
            echo "Uso: $0 [-v] [-h]"
            exit 0
            ;;
        *)
            echo "Opção inválida: $1"
            exit 1
            ;;
    esac
done

Outro exemplo com menu:

#!/bin/bash
echo "Escolha uma opção:"
echo "1) Opção 1"
echo "2) Opção 2"
echo "3) Sair"
read -p "Digite o número: " opcao
case $opcao in
    1)
        echo "Você escolheu opção 1"
        ;;
    2)
        echo "Você escolheu opção 2"
        ;;
    3)
        echo "Saindo..."
        exit 0
        ;;
    *)
        echo "Opção inválida"
        ;;
esac

Boas práticas

  • Sempre inclua um caso padrão *) para tratar entradas inesperadas.
  • Use padrões com classes de caracteres para validar entrada.
  • Para múltiplos valores, use | para combinar padrões.
  • Evite omitir ;;; mesmo que funcione em alguns casos, é propenso a erros.
  • Prefira case em vez de longas cadeias de if-elif quando a lógica for de comparação de valores.

Referências

Exercícios

  1. Escreva um script que leia uma string e use case para determinar se é "sim", "não" ou "talvez" (considere variações como "s", "n", "t").
  2. ✓ Resposta:
    #!/bin/bash
    read -p "Digite uma resposta: " resposta
    case $resposta in
        sim|s|S|Sim|SIM)
            echo "Você disse sim"
            ;;
        não|nao|n|N|Não|Nao|NAO)
            echo "Você disse não"
            ;;
        talvez|t|T|Talvez|TALVEZ)
            echo "Você disse talvez"
            ;;
        *)
            echo "Resposta não reconhecida"
            ;;
    esac
  3. Crie um script que receba um nome de arquivo como argumento e use case para exibir se a extensão é .txt, .jpg, .png ou outro.
  4. ✓ Resposta:
    #!/bin/bash
    if [ $# -eq 0 ]; then
        echo "Uso: $0 arquivo"
        exit 1
    fi
    arquivo="$1"
    case $arquivo in
        *.txt)
            echo "Arquivo de texto"
            ;;
        *.jpg|*.jpeg)
            echo "Imagem JPEG"
            ;;
        *.png)
            echo "Imagem PNG"
            ;;
        *)
            echo "Outro tipo de arquivo"
            ;;
    esac
  5. Escreva um script que simule uma calculadora simples: leia dois números e um operador (+, -, *, /) e use case para realizar a operação.
  6. ✓ Resposta:
    #!/bin/bash
    read -p "Digite o primeiro número: " num1
    read -p "Digite o operador (+, -, *, /): " op
    read -p "Digite o segundo número: " num2
    case $op in
        +)
            resultado=$((num1 + num2))
            ;;
        -)
            resultado=$((num1 - num2))
            ;;
        *)
            resultado=$((num1 * num2))
            ;;
        /)
            resultado=$((num1 / num2))
            ;;
        *)
            echo "Operador inválido"
            exit 1
            ;;
    esac
    echo "Resultado: $resultado"
  7. Desenvolva um script que leia uma string e use case para verificar se é um número, uma letra ou outro caractere (use classes de caracteres).
  8. ✓ Resposta:
    #!/bin/bash
    read -p "Digite um caractere: " char
    case $char in
        [0-9])
            echo "É um dígito"
            ;;
        [a-zA-Z])
            echo "É uma letra"
            ;;
        ?)
            echo "É um caractere especial único"
            ;;
        *)
            echo "É uma string com mais de um caractere"
            ;;
    esac
  9. Crie um script que processe argumentos de linha de comando aceitando -a (modo A), -b (modo B) e -h (ajuda), usando case dentro de um loop while.
  10. ✓ Resposta:
    #!/bin/bash
    modo=""
    while [ $# -gt 0 ]; do
        case "$1" in
            -a)
                modo="A"
                shift
                ;;
            -b)
                modo="B"
                shift
                ;;
            -h|--help)
                echo "Uso: $0 [-a] [-b] [-h]"
                exit 0
                ;;
            *)
                echo "Opção desconhecida: $1"
                exit 1
                ;;
        esac
    done
    if [ -z "$modo" ]; then
        echo "Nenhum modo selecionado"
    else
        echo "Modo selecionado: $modo"
    fi