A instrução case
Esta aula ensina a instrução case no Bash, sua sintaxe, uso de padrões glob, o conceito de fall-through e casos de uso práticos para substituir múltiplos if-elif.
A instrução case é uma estrutura de controle condicional no Bash que permite comparar uma variável ou expressão contra uma série de padrões, executando o bloco de comandos correspondente ao primeiro padrão que coincida. É uma alternativa mais limpa e eficiente a longas cadeias de if-elif, especialmente quando se deseja testar múltiplos valores discretos. Nesta aula, exploraremos sua sintaxe, o uso de padrões glob (curingas), o comportamento de fall-through (que no Bash não ocorre por padrão) e casos de uso comuns no dia a dia do shell scripting.
Sintaxe
A sintaxe básica do case é:
case EXPRESSÃO in
PADRÃO1)
COMANDOS
;;
PADRÃO2)
COMANDOS
;;
*)
COMANDOS
;;
esac
A expressão é avaliada uma vez e comparada sequencialmente com cada padrão. Cada padrão pode ser um literal, um caractere curinga (glob) ou múltiplos padrões separados por barra vertical (|). O bloco de comandos termina com dois ponto-e-vírgulas (;;), que indicam o fim daquele caso. O padrão especial * funciona como o default de outras linguagens, capturando qualquer valor não correspondido anteriormente. A estrutura é fechada com a palavra esac (case ao contrário).
Exemplo simples:
#!/bin/bash
echo "Digite um número de 1 a 3:"
read numero
case $numero in
1)
echo "Você digitou um."
;;
2)
echo "Você digitou dois."
;;
3)
echo "Você digitou três."
;;
*)
echo "Número inválido."
;;
esac
Padrões (globs)
Os padrões no case são expressões glob, semelhantes às usadas em nomes de arquivos no shell. Eles permitem correspondências flexíveis:
*- corresponde a qualquer sequência de caracteres (inclusive vazia).?- corresponde a exatamente um caractere.[abc]- corresponde a um dos caracteres listados (a, b ou c).[a-z]- corresponde a qualquer caractere no intervalo.[!abc]- corresponde a qualquer caractere exceto os listados.
Exemplo com padrões:
#!/bin/bash
echo "Digite um caractere:"
read char
case $char in
[a-z])
echo "Letra minúscula."
;;
[A-Z])
echo "Letra maiúscula."
;;
[0-9])
echo "Dígito."
;;
*)
echo "Outro caractere."
;;
esac
Múltiplos padrões podem ser combinados com | para executar o mesmo bloco para diferentes valores:
#!/bin/bash
echo "Digite sim, não ou talvez:"
read resposta
case $resposta in
sim|s|S|Sim|SIM)
echo "Resposta positiva."
;;
não|não|n|N|Não|NÃO)
echo "Resposta negativa."
;;
talvez|t|T|Talvez|TALVEZ)
echo "Resposta ambígua."
;;
*)
echo "Resposta desconhecida."
;;
esac
Fall-through
Diferentemente de linguagens como C, o case do Bash não executa fall-through automaticamente. Cada caso termina com ;;, que interrompe a execução e sai da estrutura. Se você omitir o ;;, o script continuará executando os comandos do próximo caso, mas isso geralmente é considerado um erro (a menos que intencional). Para simular fall-through, pode-se usar ;& (continue testando os próximos padrões) ou ;;& (continue executando os próximos comandos sem testar).
Exemplo com ;&:
#!/bin/bash
echo "Digite um número:"
read num
case $num in
1)
echo "Um"
;;& # continua testando os próximos padrões
2)
echo "Dois"
;;&
3)
echo "Três"
;;&
*)
echo "Número: $num"
;;
esac
Com ;;&, todos os casos a partir do primeiro coincidente são executados:
#!/bin/bash
echo "Digite um número:"
read num
case $num in
1)
echo "Primeiro caso"
;;& # continua executando os próximos blocos
2)
echo "Segundo caso"
;;&
3)
echo "Terceiro caso"
;;&
*)
echo "Último caso"
;;
esac
Casos de uso
O case é ideal para menus interativos, processamento de argumentos de linha de comando, tratamento de opções e validação de entrada. Exemplo de menu:
#!/bin/bash
while true; do
echo "Escolha uma opção:"
echo "1. Listar arquivos"
echo "2. Mostrar data"
echo "3. Sair"
read opcao
case $opcao in
1)
ls -l
;;
2)
date
;;
3)
echo "Saindo..."
break
;;
*)
echo "Opção inválida."
;;
esac
done
Outro uso comum é processar argumentos de script com getopts ou manualmente:
#!/bin/bash
for arg in "$@"; do
case $arg in
-h|--help)
echo "Uso: $0 [-v] [-o arquivo]"
exit 0
;;
-v|--verbose)
VERBOSE=true
;;
-o|--output)
shift
OUTPUT=$1
;;
*)
echo "Argumento desconhecido: $arg"
exit 1
;;
esac
done
Boas práticas
- Sempre use
;;para encerrar cada caso, a menos que intencionalmente queira fall-through. - Coloque o padrão
*)como último para capturar entradas inesperadas. - Indente os comandos dentro de cada caso para legibilidade.
- Use
|para agrupar padrões que levam ao mesmo resultado. - Para scripts portáveis, evite
;&e;;&, pois não são POSIX.
Referências
- GNU Bash Manual: Conditional Constructs
- Advanced Bash-Scripting Guide: Case Selection
- BashGuide: Case Statement
- ShellCheck - ferramenta de análise estática para scripts shell
- POSIX Shell Command Language - Case Conditional
Exercícios
- Escreva um script que use
casepara exibir o nome do dia da semana (em português) com base em um número de 1 a 7 fornecido pelo usuário. Inclua tratamento para entradas inválidas. - Crie um script que leia uma string e use
casepara determinar se ela começa com uma vogal, consoante, dígito ou outro caractere. Use padrões glob. - Escreva um script que simule um sistema de login simples. O usuário deve digitar um nome de usuário e, usando
case, o script deve exibir uma mensagem personalizada para pelo menos três usuários diferentes (ex.: admin, guest, user) e uma mensagem padrão para outros. - Crie um script que aceite um argumento de linha de comando e use
casepara interpretar as opções-a,-be-c, exibindo uma mensagem para cada. Se nenhuma opção for fornecida, exiba uma mensagem de uso. - Escreva um script que leia uma string e use
casepara verificar se ela é exatamente "sim", "não" ou "talvez" (em qualquer combinação de maiúsculas/minúsculas). Use múltiplos padrões com|.
#!/bin/bash
echo "Digite um número de 1 a 7:"
read num
case $num in
1) echo "Domingo" ;;
2) echo "Segunda-feira" ;;
3) echo "Terça-feira" ;;
4) echo "Quarta-feira" ;;
5) echo "Quinta-feira" ;;
6) echo "Sexta-feira" ;;
7) echo "Sábado" ;;
*) echo "Número inválido. Digite um valor entre 1 e 7." ;;
esac
#!/bin/bash
echo "Digite uma string:"
read string
primeiro=${string:0:1}
case $primeiro in
[aeiouAEIOU]) echo "Começa com vogal." ;;
[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]) echo "Começa com consoante." ;;
[0-9]) echo "Começa com dígito." ;;
*) echo "Começa com outro caractere." ;;
esac
#!/bin/bash
echo "Digite seu nome de usuário:"
read usuario
case $usuario in
admin) echo "Bem-vindo, administrador! Acesso total." ;;
guest) echo "Bem-vindo, convidado! Acesso limitado." ;;
user) echo "Bem-vindo, usuário! Acesso padrão." ;;
*) echo "Usuário desconhecido. Acesso negado." ;;
esac
#!/bin/bash
if [ $# -eq 0 ]; then
echo "Uso: $0 [-a|-b|-c]"
exit 1
fi
case $1 in
-a) echo "Opção A selecionada." ;;
-b) echo "Opção B selecionada." ;;
-c) echo "Opção C selecionada." ;;
*) echo "Opção inválida: $1. Use -a, -b ou -c." ;;
esac
#!/bin/bash
echo "Digite sim, não ou talvez:"
read resposta
case $resposta in
sim|s|S|Sim|SIM) echo "Resposta positiva." ;;
não|não|n|N|Não|NÃO) echo "Resposta negativa." ;;
talvez|t|T|Talvez|TALVEZ) echo "Resposta ambígua." ;;
*) echo "Resposta não reconhecida." ;;
esac