Revisão de boas práticas
LidoEsta aula final consolida as boas práticas de shell script, oferecendo um checklist de qualidade, estratégias de manutenibilidade, documentação eficaz e versionamento com Git. O objetivo é transformar scripts funcionais em software confiável e sustentável.
Chegamos à reta final do nosso curso! Ao longo de 97 aulas, você aprendeu a criar scripts poderosos, automatizar tarefas, manipular textos, lidar com erros e muito mais. Mas um script que funciona é apenas o começo. Nesta aula de revisão, vamos consolidar as boas práticas que separam um código amador de um profissional. Vamos pensar além da funcionalidade: qualidade, manutenção, documentação e versionamento são os pilares para que seus scripts sejam confiáveis, legíveis e evoluam sem dor de cabeça.
Este é o momento de internalizar hábitos que vão te acompanhar em qualquer projeto, seja um script de 10 linhas ou um sistema complexo. Vamos mergulhar em cada um desses pilares, com exemplos práticos e referências para aprofundamento.
Checklist de qualidade
Antes de considerar um script 'pronto', é essencial passar por um checklist que garanta sua robustez e aderência a padrões. Isso evita surpresas em produção e facilita a vida de quem for usar (incluindo o seu 'eu' do futuro). Abaixo, uma lista de verificação que você pode aplicar a qualquer script.
- Shebang correto:
#!/usr/bin/env bashpara portabilidade ou caminho absoluto. - Opções do shell:
set -euo pipefailpara sair em erros, tratar variáveis não definidas e falhas em pipelines. - Variáveis globais em MAIÚSCULAS: facilita a identificação.
- Funções nomeadas com verbos:
processar_arquivo(),validar_entrada(). - Tratamento de argumentos: usar
getoptsou validação manual com mensagens de uso. - Checagem de dependências: verificar se comandos externos existem.
- Mensagens de erro claras: incluir contexto e sair com código de status apropriado.
- Sem execução desnecessária com privilégios: evitar
sudodentro do script, a menos que necessário. - Código limpo e indentado: consistência no uso de espaços ou tabs.
- Tratamento de sinais: usar
trappara limpar recursos temporários.
Exemplo de estrutura inicial de um script seguindo o checklist:
#!/usr/bin/env bash
set -euo pipefail
# Constantes
readonly SCRIPT_NOME="$(basename "$0")"
readonly DIR_TEMP="$(mktemp -d)"
# Trap para limpeza
trap 'rm -rf "$DIR_TEMP"' EXIT
# Funções
ajuda() {
cat <<EOF
Uso: $SCRIPT_NOME [opções]
Opções:
-h, --help Mostra esta ajuda
EOF
}
# Verificação de dependências
for cmd in curl jq; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Erro: comando '$cmd' não encontrado. Instale-o para continuar." >&2
exit 1
fi
done
# Processamento de argumentos
while getopts ":h" opt; do
case "$opt" in
h)
ajuda
exit 0
;;
\?)
echo "Opção inválida: -$OPTARG" >&2
ajuda
exit 1
;;
esac
done
# Corpo principal
...
EOF
Aplicar esse checklist sistematicamente reduz bugs e melhora a experiência de quem mantém o código. Lembre-se: qualidade não é acidental, é uma decisão consciente.
Manutenibilidade
Um script manutenível é aquele que pode ser entendido, modificado e estendido com facilidade. Isso exige organização, simplicidade e consistência. Scripts longos e monolíticos são difíceis de depurar e arriscados de alterar. A chave é dividir o problema em partes menores.
Princípios de manutenibilidade:
- Modularização: quebre o script em funções pequenas e coesas. Cada função deve fazer apenas uma coisa.
- Nomes descritivos: evite
x,y; usearquivo_entrada,usuario. - Comentários estratégicos: explique o 'porquê', não o 'o quê'. O código já mostra o que faz.
- Evite duplicação: se você copiou e colou, extraia para uma função.
- Use constantes para valores mágicos: em vez de
if [[ $? -eq 0 ]], usereadonly SUCESSO=0.
Exemplo de refatoração de um trecho duplicado:
# Antes: código duplicado para validar arquivos
if [[ -f "$1" ]]; then
echo "Processando $1"
fi
if [[ -f "$2" ]]; then
echo "Processando $2"
fi
# Depois: função reutilizável
processar_arquivo() {
local arquivo="$1"
if [[ -f "$arquivo" ]]; then
echo "Processando $arquivo"
else
echo "Aviso: arquivo $arquivo não encontrado" >&2
fi
}
processar_arquivo "$1"
processar_arquivo "$2"
Outra prática recomendada é usar o shellcheck para análise estática. Ele aponta erros comuns e sugere melhorias. Integrá-lo ao seu fluxo de trabalho é um passo enorme para a qualidade.
# Instalar (exemplo no Ubuntu)
sudo apt install shellcheck
# Usar
shellcheck script.sh
Manutenibilidade não é um luxo, é uma necessidade para projetos que crescem. Invista tempo em escrever código claro e você colherá os frutos no futuro.
Documentação
Documentação é a ponte entre o código e os seres humanos. Ela pode ser interna (comentários) e externa (README, man pages). Um script bem documentado é mais confiável e mais fácil de adotar. Mas documentar bem não é despejar texto; é fornecer informações relevantes de forma organizada.
Documentação interna:
- Cabeçalho do script: incluir nome, descrição, autor, data, versão e como usar.
- Comentários em trechos complexos: explique a lógica, especialmente se não for óbvia.
- Documentação de funções: descrever parâmetros, retorno e efeitos colaterais.
#!/usr/bin/env bash
#===============================================================================
# backup.sh - Cria backup compactado de um diretório
#
# Uso: ./backup.sh <diretorio_origem> <arquivo_destino>
#
# Exemplo:
# ./backup.sh /home/user/documentos /backup/documentos.tar.gz
#
# Autor: João Silva
# Data: 2025-01-01
# Versão: 1.0
#===============================================================================
# Função para validar argumentos
# Uso: validar_args "$@"
# Retorna 0 se ok, 1 se erro
validar_args() {
if [[ $# -ne 2 ]]; then
echo "Erro: número de argumentos inválido." >&2
exit 1
fi
}
Documentação externa:
- README.md: com visão geral, instalação, uso, exemplos e link para mais informações.
- Man pages: para scripts distribuídos, criar uma página de manual usando
pandocouronn. - Wiki ou docs online: para projetos maiores.
Além disso, use a opção --help em seus scripts, fornecendo uma mensagem de ajuda clara. Isso é documentação viva, acessível ao usuário.
# Trecho de exemplo
ajuda() {
cat <<EOF
Uso: $(basename "$0") [OPÇÕES]
Opções:
-h, --help Exibe esta ajuda
-v, --verbose Modo verboso
EOF
}
# No processamento de argumentos
-h|--help)
ajuda
exit 0
;;
Documentar é um ato de respeito com quem vai usar e manter o código. Não pule essa etapa.
Versionamento
Versionar seus scripts com Git é essencial para acompanhar mudanças, colaborar e reverter para versões anteriores quando necessário. Mesmo scripts pessoais se beneficiam do controle de versão. Nesta seção, vamos revisar as práticas recomendadas para versionar scripts shell.
Configuração inicial:
- Inicie um repositório:
git initno diretório do projeto. - Crie um .gitignore: para excluir arquivos temporários e sensíveis.
- Faça commits pequenos e frequentes: com mensagens descritivas.
Exemplo de .gitignore para scripts:
# Arquivos temporários
*.tmp
*.log
# Diretórios de backup
backups/
# Arquivos de ambiente
.env
Boas práticas de commit:
- Mensagens claras: use o imperativo: "Adiciona função de validação".
- Separe mudanças lógicas: um commit por tarefa.
- Use branches: para experimentos ou novas funcionalidades.
- Tags para versões:
git tag v1.0.0para releases.
Além disso, considere usar hooks do Git, como um hook de pre-commit que roda o shellcheck automaticamente. Isso garante que o código commitado siga padrões de qualidade.
# .git/hooks/pre-commit (exemplo)
#!/usr/bin/env bash
# Executa shellcheck em todos os scripts .sh modificados
for file in $(git diff --cached --name-only -- '*.sh'); do
if ! shellcheck "$file"; then
echo "Erro: shellcheck falhou em $file" >&2
exit 1
fi
done
exit 0
O versionamento também facilita a revisão de código e a colaboração em equipe. Mesmo que você trabalhe sozinho, o Git é um seguro contra desastres.
Boas práticas finais
Além dos pilares acima, aqui vão algumas observações finais para elevar ainda mais a qualidade dos seus scripts:
- Teste seus scripts: escreva testes simples ou use ferramentas como
shunit2. - Considere o uso de frameworks: como
bashunitpara estruturação. - Mantenha a compatibilidade: teste com diferentes versões do Bash e em outras plataformas (se possível).
- Pense em segurança: evite injeção de comandos usando arrays e aspas corretamente.
- Compartilhe e aprenda: publique seus scripts em plataformas como GitHub para receber feedback.
Lembre-se: a prática leva à perfeição. Continue escrevendo, refatorando e melhorando seus scripts. As boas práticas se tornam hábitos com o tempo, e você verá seus scripts se tornarem mais confiáveis e fáceis de manter.
Referências
- Bash Reference Manual (GNU)
- ShellCheck - Shell Script Analysis Tool
- Git Documentation
- Advanced Bash-Scripting Guide
- Google Shell Style Guide
- bash(1) - Linux man page
- ShellCheck no GitHub
Exercícios
-
Refatore o seguinte script para seguir as boas práticas de qualidade (use
set -euo pipefail, funções, validação de argumentos, etc.):#!/bin/bash # Script antigo cp $1 $2 echo "Arquivo copiado"✓ Resposta:#!/usr/bin/env bash set -euo pipefail # Função de uso uso() { cat <<EOF Uso: $(basename "$0") <origem> <destino> EOF exit 1 } # Validação de argumentos [[ $# -eq 2 ]] || uso origem="$1" destino="$2" # Verifica se origem existe if [[ ! -f "$origem" ]]; then echo "Erro: arquivo origem '$origem' não encontrado." >&2 exit 1 fi cp "$origem" "$destino" echo "Arquivo copiado com sucesso." -
Adicione documentação interna (cabeçalho e comentários) ao script abaixo, explicando o que ele faz e como usar:
#!/usr/bin/env bash # Script sem documentação find /var/log -name "*.log" -mtime +7 -exec rm {} \; echo "Logs antigos removidos."✓ Resposta:#!/usr/bin/env bash #=============================================================================== # limpar_logs.sh - Remove arquivos .log antigos (mais de 7 dias) do diretório /var/log # # Uso: ./limpar_logs.sh # # Este script percorre /var/log, encontra arquivos .log com mais de 7 dias e os exclui. # Cuidado: a exclusão é permanente. Use com responsabilidade. # # Autor: Seu Nome # Data: 2025-01-01 # Versão: 1.0 #=============================================================================== set -euo pipefail # Diretório de logs (pode ser alterado) LOG_DIR="/var/log" # Remove arquivos .log modificados há mais de 7 dias find "$LOG_DIR" -name "*.log" -mtime +7 -exec rm {} \; echo "Logs antigos removidos com sucesso." -
Escreva um script que use um
trappara limpar um arquivo temporário ao sair (considere os sinais EXIT e INT).✓ Resposta:#!/usr/bin/env bash set -euo pipefail # Cria arquivo temporário TEMP_FILE="$(mktemp)" # Função de limpeza limpar() { rm -f "$TEMP_FILE" echo "Arquivo temporário removido." } # Registra a limpeza para os sinais EXIT e INT trap limpar EXIT INT # Simula algum trabalho echo "Trabalhando..." sleep 5 # O trap será chamado ao final ou se o script for interrompido -
Explique a importância de usar
set -euo pipefaile dê um exemplo de como ele evita erros silenciosos.✓ Resposta:set -efaz o script sair imediatamente se qualquer comando retornar um status diferente de zero.-utrata o uso de variáveis não definidas como erro.-o pipefailfaz com que o pipeline retorne o status do último comando que falhou, em vez do último comando. Isso evita que erros sejam ignorados silenciosamente, como no exemplo:#!/usr/bin/env bash # Sem pipefail false | echo "Isso ainda executa" echo "O script continua mesmo com erro." # Com pipefail set -o pipefail false | echo "Isso executa, mas o pipeline falha" echo "Este comando não será alcançado." -
Crie um script que use
getoptspara aceitar as opções-v(verbose) e-h(help), e que imprima uma mensagem diferente se-vfor passado.✓ Resposta:#!/usr/bin/env bash set -euo pipefail VERBOSE=false uso() { cat <<EOF Uso: $(basename "$0") [-v] [-h] Opções: -v Modo verboso -h Exibe esta ajuda EOF exit 0 } while getopts ":vh" opt; do case "$opt" in v) VERBOSE=true ;; h) uso ;; \?) echo "Opção inválida: -$OPTARG" >&2 uso ;; esac done if [[ "$VERBOSE" == true ]]; then echo "Modo verboso ativado." else echo "Execução normal." fi