Case statement em Bash

1. Introdução ao Case Statement

O comando case é uma estrutura de controle condicional presente no Bash que permite comparar uma variável ou expressão contra múltiplos padrões de forma clara e eficiente. Diferentemente de longas cadeias de if-elif-else, o case oferece uma sintaxe mais legível e enxuta para situações onde se deseja testar diversos valores possíveis para uma mesma variável.

A sintaxe básica do case segue o seguinte formato:

case expressao in
    padrao1)
        comandos
        ;;
    padrao2)
        comandos
        ;;
    *)
        comandos_padrao
        ;;
esac

A principal vantagem do case sobre o if-elif-else é a clareza visual: cada padrão é claramente delimitado, e o uso do ;; evita ambiguidades sobre onde termina cada bloco de comandos. Além disso, o case suporta padrões com curingas, tornando-o mais flexível para correspondências parciais.

2. Sintaxe e Estrutura do Case

A estrutura do case é composta por palavras-chave específicas:

  • case: inicia o bloco, seguido pela expressão a ser avaliada
  • in: separa a expressão dos padrões
  • ;;: finaliza cada bloco de comandos de um padrão
  • esac: fecha o bloco case (é "case" ao contrário)

Os padrões podem ser literais, curingas ou combinações:

#!/bin/bash

fruta="banana"

case $fruta in
    "maca")
        echo "É uma maçã"
        ;;
    "banana"|"laranja")
        echo "É uma banana ou laranja"
        ;;
    *)
        echo "Fruta desconhecida"
        ;;
esac

O padrão *) funciona como um "else" genérico, capturando qualquer valor que não corresponda aos padrões anteriores. É boa prática sempre incluir um padrão curinga ao final.

3. Padrões com Caracteres Curinga

O Bash permite o uso de caracteres curinga dentro dos padrões do case, seguindo as regras de globbing:

  • *: corresponde a qualquer sequência de caracteres
  • ?: corresponde a exatamente um caractere
  • |: combina múltiplos padrões em um único bloco
#!/bin/bash

read -p "Digite um nome de arquivo: " arquivo

case $arquivo in
    *.txt)
        echo "Arquivo de texto"
        ;;
    *.jpg|*.png|*.gif)
        echo "Arquivo de imagem"
        ;;
    arquivo?)
        echo "Arquivo com nome de 8 caracteres"
        ;;
    *)
        echo "Tipo desconhecido"
        ;;
esac

Note que arquivo? corresponderia a "arquivo1", "arquivoA", mas não a "arquivo" ou "arquivo12". O curinga ? é útil para validar formatos específicos de entrada.

4. Case com Expressões Regulares e Globbing

É importante entender que o case do Bash utiliza globbing (expansão de padrões de arquivos) e não expressões regulares. No globbing, podemos usar classes de caracteres entre colchetes:

  • [abc]: corresponde a 'a', 'b' ou 'c'
  • [0-9]: corresponde a qualquer dígito
  • [[:alpha:]]: corresponde a qualquer letra
  • [[:upper:]]: corresponde a letras maiúsculas
#!/bin/bash

read -p "Digite uma senha: " senha

case $senha in
    [0-9]*)
        echo "Senha começa com número"
        ;;
    [[:upper:]]*)
        echo "Senha começa com letra maiúscula"
        ;;
    ?[[:digit:]])
        echo "Senha tem 2 caracteres e o segundo é dígito"
        ;;
    *)
        echo "Formato não identificado"
        ;;
esac

Diferentemente das expressões regulares, no globbing não usamos âncoras como ^ ou $. O padrão é aplicado contra a string inteira.

5. Case com Variáveis e Argumentos de Script

O case é extremamente útil para processar argumentos de linha de comando e criar menus interativos:

#!/bin/bash

# Processando argumentos do script
case $1 in
    -h|--help)
        echo "Uso: $0 [OPCAO]"
        echo "Opções:"
        echo "  -h, --help     Mostra esta ajuda"
        echo "  -v, --version  Mostra a versão"
        echo "  -l, --list     Lista itens"
        ;;
    -v|--version)
        echo "Script versão 1.0"
        ;;
    -l|--list)
        for item in "$@"; do
            [ "$item" = "$1" ] && continue
            echo "Item: $item"
        done
        ;;
    *)
        echo "Opção inválida: $1"
        echo "Use $0 --help para ajuda"
        exit 1
        ;;
esac

Para menus interativos com read:

#!/bin/bash

echo "=== MENU PRINCIPAL ==="
echo "1) Iniciar serviço"
echo "2) Parar serviço"
echo "3) Status do serviço"
echo "4) Sair"
read -p "Escolha uma opção: " opcao

case $opcao in
    1)
        echo "Iniciando serviço..."
        # Comando para iniciar
        ;;
    2)
        echo "Parando serviço..."
        # Comando para parar
        ;;
    3)
        echo "Verificando status..."
        # Comando para status
        ;;
    4|s|S|sair|SAIR)
        echo "Saindo..."
        exit 0
        ;;
    *)
        echo "Opção inválida!"
        ;;
esac

6. Boas Práticas e Armadilhas Comuns

Esquecer o ;;: Este é o erro mais comum. Sem o ;;, o Bash continua executando os comandos do próximo padrão (fall-through):

# ERRADO - sem ;;
case $var in
    a)
        echo "Opção A"
        # Falta o ;;
    b)
        echo "Opção B"  # Será executado mesmo se $var for "a"
        ;;
esac

Ordem dos padrões: Coloque padrões mais específicos antes dos genéricos:

# ERRADO - padrão genérico antes
case $ext in
    *)
        echo "Tipo desconhecido"
        ;;
    .txt)
        echo "Arquivo texto"  # Nunca será executado
        ;;
esac

Uso do esac: Lembre-se que esac é obrigatório para fechar o bloco. É uma palavra invertida de case, fácil de memorizar.

7. Exemplos Práticos e Aplicações

Script de menu de sistema (start/stop/status):

#!/bin/bash

SERVICO="apache2"

case $1 in
    start)
        echo "Iniciando $SERVICO..."
        systemctl start $SERVICO
        ;;
    stop)
        echo "Parando $SERVICO..."
        systemctl stop $SERVICO
        ;;
    restart)
        echo "Reiniciando $SERVICO..."
        systemctl restart $SERVICO
        ;;
    status)
        systemctl status $SERVICO
        ;;
    *)
        echo "Uso: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

Validação de entrada do usuário (sim/não/sair):

#!/bin/bash

read -p "Deseja continuar? (s/n/sair): " resposta

case $resposta in
    s|S|sim|SIM|Sim)
        echo "Continuando execução..."
        ;;
    n|N|nao|NAO|Nao)
        echo "Operação cancelada."
        ;;
    sair|exit|quit)
        echo "Encerrando script."
        exit 0
        ;;
    *)
        echo "Resposta inválida. Use s, n ou sair."
        ;;
esac

Processamento de extensões de arquivo:

#!/bin/bash

for arquivo in "$@"; do
    case "$arquivo" in
        *.txt)
            echo "Processando $arquivo como texto..."
            cat "$arquivo"
            ;;
        *.jpg|*.jpeg|*.png)
            echo "Processando $arquivo como imagem..."
            file "$arquivo"
            ;;
        *.pdf)
            echo "Processando $arquivo como PDF..."
            pdftotext "$arquivo" - | head -5
            ;;
        *.sh)
            echo "Verificando sintaxe do script $arquivo..."
            bash -n "$arquivo"
            ;;
        *)
            echo "Extensão não reconhecida para $arquivo"
            ;;
    esac
done

O case no Bash é uma ferramenta poderosa que, quando bem utilizada, torna scripts mais legíveis, organizados e fáceis de manter. Combinado com curingas e classes de caracteres, oferece flexibilidade para lidar com uma ampla gama de padrões de entrada, superando as limitações de cadeias longas de if-elif-else.

Referências