A instrução case
Nesta aula, exploramos a instrução case no Bash, que permite selecionar um bloco de comandos com base em uma expressão, comparando-a com padrões glob. Abordamos sua sintaxe, o uso de padrões com curingas, a ausência de fall-through (diferente de outras linguagens) e os principais casos de uso, como processamento de argumentos e entrada do usuário.
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
caseem vez de longas cadeias deif-elifquando a lógica for de comparação de valores.
Referências
- GNU Bash Manual: Conditional Constructs
- Bash Beginners Guide: Case statements
- Wooledge BashGuide: Patterns
- Shell Scripting Tutorial: Case
- Devhints: Bash case statement
Exercícios
- 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").
- 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.
- Escreva um script que simule uma calculadora simples: leia dois números e um operador (+, -, *, /) e use case para realizar a operação.
- 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).
- 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.
#!/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
#!/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
#!/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"
#!/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
#!/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