Validando entradas
Nesta aula, você aprenderá a validar entradas em scripts shell, incluindo verificação de argumentos, definição de valores obrigatórios e criação de mensagens de uso claras. São apresentados exemplos práticos e boas práticas para tornar seus scripts mais robustos e confiáveis.
Validar entradas é uma etapa essencial no desenvolvimento de scripts shell robustos. Sem validação adequada, seu script pode falhar de maneiras imprevisíveis ou causar danos acidentais. Nesta aula, vamos explorar técnicas para verificar argumentos, garantir que valores obrigatórios sejam fornecidos e exibir mensagens de uso informativas.
A validação de entrada não apenas previne erros, mas também melhora a experiência do usuário, fornecendo feedback claro sobre como usar o script corretamente. Vamos começar com os fundamentos e avançar para exemplos práticos.
Verificando argumentos
Em scripts shell, os argumentos passados na linha de comando são acessados através das variáveis posicionais: $1, $2, ..., $9 (e ${10} para o décimo em diante). O número total de argumentos é armazenado em $#. A verificação básica envolve checar se $# é igual ao número esperado ou está dentro de um intervalo.
Por exemplo, para verificar se pelo menos um argumento foi fornecido:
if [ $# -lt 1 ]; then
echo "Erro: É necessário pelo menos um argumento."
exit 1
fiTambém é possível verificar se um argumento específico não está vazio:
if [ -z "$1" ]; then
echo "Erro: O primeiro argumento não pode estar vazio."
exit 1
fiOutra técnica comum é usar ! -z para verificar se a string não está vazia ou -n (equivalente a não vazio).
Valores obrigatórios
Muitas vezes, um script exige que certos argumentos sejam fornecidos. Você pode definir variáveis com valores padrão ou exigir que o usuário forneça todos os parâmetros necessários. Uma abordagem comum é usar um loop para processar argumentos nomeados (flags) como -f ou --file, mas aqui focaremos em argumentos posicionais.
Suponha um script que requer um nome de arquivo e um diretório de destino:
if [ $# -ne 2 ]; then
echo "Erro: Uso: $0 <arquivo> <diretorio>"
exit 1
fi
arquivo="$1"
diretorio="$2"
# Verifica se o arquivo existe
if [ ! -f "$arquivo" ]; then
echo "Erro: Arquivo '$arquivo' não encontrado."
exit 1
fi
# Verifica se o diretório existe
if [ ! -d "$diretorio" ]; then
echo "Erro: Diretório '$diretorio' não existe."
exit 1
fiAlém de verificar a presença, é importante validar o tipo de dado. Por exemplo, se um argumento deve ser um número, use uma expressão regular ou case:
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
echo "Erro: O argumento deve ser um número inteiro."
exit 1
fiMensagens de uso
Uma mensagem de uso (ou "usage") informa o usuário sobre como executar o script corretamente. Ela deve ser exibida quando argumentos inválidos são fornecidos ou quando a opção -h ou --help é usada. Uma boa prática é definir uma função para exibir a mensagem.
usage() {
echo "Uso: $0 [OPÇÕES] <arquivo>"
echo ""
echo "OPÇÕES:"
echo " -h, --help Exibe esta ajuda"
echo " -v, --verbose Modo verboso"
echo ""
echo "Exemplo:"
echo " $0 -v dados.txt"
exit 1
}
# Processa opções simples
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
-v|--verbose)
verbose=true
shift
;;
-*)
echo "Opção desconhecida: $1"
usage
;;
*)
break
;;
esac
done
# Verifica se resta um argumento (o arquivo)
if [ $# -ne 1 ]; then
usage
fi
arquivo="$1"A função usage pode ser chamada sempre que houver erro de validação, garantindo consistência.
Exemplos
Vamos consolidar os conceitos com um script completo que valida entradas para copiar um arquivo para um diretório, com opção de backup.
#!/bin/bash
# Função de uso
usage() {
echo "Uso: $0 [OPÇÕES] <arquivo_origem> <diretorio_destino>"
echo "Copia um arquivo para um diretório."
echo ""
echo "OPÇÕES:"
echo " -b, --backup Cria um backup antes de copiar"
echo " -h, --help Exibe esta ajuda"
exit 1
}
# Variáveis
backup=false
# Processa opções
while [[ $# -gt 0 ]]; do
case $1 in
-b|--backup)
backup=true
shift
;;
-h|--help)
usage
;;
-*)
echo "Opção inválida: $1"
usage
;;
*)
break
;;
esac
done
# Verifica argumentos obrigatórios
if [ $# -ne 2 ]; then
echo "Erro: Número incorreto de argumentos."
usage
fi
origem="$1"
destino="$2"
# Valida origem
if [ ! -f "$origem" ]; then
echo "Erro: Arquivo de origem '$origem' não existe."
exit 1
fi
# Valida destino
if [ ! -d "$destino" ]; then
echo "Erro: Diretório de destino '$destino' não existe."
exit 1
fi
# Se backup for solicitado, faz backup
if [ "$backup" = true ]; then
timestamp=$(date +%Y%m%d%H%M%S)
backup_file="${destino}/${origem##*/}.backup.$timestamp"
cp "$origem" "$backup_file"
echo "Backup criado em $backup_file"
fi
# Copia o arquivo
cp "$origem" "$destino"
echo "Arquivo copiado com sucesso."Neste exemplo, validamos a existência do arquivo de origem e do diretório de destino, além de verificar o número correto de argumentos. A opção -b é opcional e tratada antes dos argumentos posicionais.
Boas práticas
Sempre valide entradas o mais cedo possível no script. Use saídas com código de erro diferente de zero para indicar falhas. Forneça mensagens de erro claras e específicas. Considere usar set -e para sair em caso de erro, mas com cuidado para não mascarar validações.
Referências
- GNU Bash Manual: Shell Parameters
- Advanced Bash-Scripting Guide
- Bash Hackers Wiki: Positional Parameters
- ShellCheck - Ferramenta de análise estática para scripts shell
- Google Shell Style Guide
- DevHints: Bash scripting cheatsheet
Exercícios
Crie um script que aceite exatamente dois argumentos: um nome de arquivo e uma string. O script deve verificar se o arquivo existe e se a string não está vazia. Em caso de erro, exiba uma mensagem de uso.
✓ Resposta:#!/bin/bash if [ $# -ne 2 ]; then echo "Uso: $0 <arquivo> <string>" exit 1 fi if [ ! -f "$1" ]; then echo "Erro: Arquivo '$1' não encontrado." exit 1 fi if [ -z "$2" ]; then echo "Erro: A string não pode estar vazia." exit 1 fi echo "Sucesso: Arquivo '$1' existe e string '$2' fornecida."Escreva um script que aceite um número inteiro como argumento. Valide se o argumento é um número inteiro positivo. Caso contrário, exiba uma mensagem de erro e saia.
✓ Resposta:#!/bin/bash if [ $# -ne 1 ]; then echo "Uso: $0 <número>" exit 1 fi if ! [[ "$1" =~ ^[0-9]+$ ]]; then echo "Erro: '$1' não é um número inteiro positivo." exit 1 fi echo "Número válido: $1"Modifique o script do exercício 1 para aceitar uma opção
-v(verbose) que, quando ativada, exiba mensagens detalhadas durante a validação.✓ Resposta:#!/bin/bash verbose=false while [[ $# -gt 0 ]]; do case $1 in -v) verbose=true shift ;; -*) echo "Opção inválida: $1" exit 1 ;; *) break ;; esac done if [ $# -ne 2 ]; then echo "Uso: $0 [-v] <arquivo> <string>" exit 1 fi if [ ! -f "$1" ]; then echo "Erro: Arquivo '$1' não encontrado." exit 1 fi if [ -z "$2" ]; then echo "Erro: A string não pode estar vazia." exit 1 fi if [ "$verbose" = true ]; then echo "Arquivo '$1' existe." echo "String '$2' não vazia." fi echo "Validação concluída com sucesso."Crie um script que aceite uma lista de números separados por espaço. Valide se cada argumento é um número inteiro. Se algum não for, exiba uma mensagem de erro e pare.
✓ Resposta:#!/bin/bash for arg in "$@"; do if ! [[ "$arg" =~ ^-?[0-9]+$ ]]; then echo "Erro: '$arg' não é um número inteiro." exit 1 fi done echo "Todos os argumentos são números inteiros válidos."Desenvolva um script que simule um comando de cópia com validação: aceite dois argumentos (origem e destino). Verifique se a origem é um arquivo regular e se o destino é um diretório. Se o destino não existir, crie-o (com permissão padrão). Se a origem não existir, exiba erro.
✓ Resposta:#!/bin/bash if [ $# -ne 2 ]; then echo "Uso: $0 <origem> <destino>" exit 1 fi origem="$1" destino="$2" if [ ! -f "$origem" ]; then echo "Erro: Origem '$origem' não é um arquivo regular." exit 1 fi if [ ! -d "$destino" ]; then mkdir -p "$destino" || { echo "Erro ao criar diretório '$destino'."; exit 1; } echo "Diretório '$destino' criado." fi cp "$origem" "$destino" echo "Arquivo copiado para '$destino'."