Estruturando scripts profissionais
Esta aula ensina como estruturar scripts bash profissionais, abordando cabeçalho e documentação, uso de funções, função main() e constantes, com exemplos práticos e boas práticas de organização.
Escrever scripts bash que sejam fáceis de manter, entender e reutilizar é uma habilidade essencial para qualquer profissional de TI. Nesta aula, você aprenderá a estruturar scripts de forma profissional, aplicando técnicas como cabeçalho documentado, funções bem definidas, função main() e uso de constantes. Essas práticas transformam scripts simples em programas robustos, prontos para ambientes de produção.
Vamos explorar cada elemento com exemplos práticos, mostrando como a organização do código impacta na legibilidade, depuração e escalabilidade. Ao final, você terá um modelo de script profissional que pode servir de base para seus projetos.
Cabeçalho e documentação
O cabeçalho de um script bash é a primeira impressão que outros desenvolvedores terão do seu código. Um cabeçalho bem elaborado deve conter informações essenciais sobre o script: nome, descrição, autor, data, versão, licença e como usá-lo. Isso não é apenas uma formalidade; documentação clara reduz o tempo de onboarding e evita erros de uso.
Além do cabeçalho, é importante documentar o código ao longo do script, explicando a lógica de partes complexas. Comentários devem ser objetivos e úteis, não apenas repetir o que o código faz. Uma boa prática é usar comentários para explicar o porquê, não o como.
Exemplo de cabeçalho profissional:
#!/usr/bin/env bash
#
# Script: backup.sh
# Descrição: Realiza backup de diretórios para um local remoto.
# Autor: João Silva
# Data: 2025-01-15
# Versão: 1.0.0
# Licença: MIT
# Uso: ./backup.sh [diretório_origem] [destino]
# Dependências: rsync, tar
#
# Este script executa um backup incremental usando rsync.
# O diretório de origem é compactado e enviado ao destino.
#
# Exemplos:
# ./backup.sh /home/user/docs /mnt/backup
# ./backup.sh --help
#Note o uso de #!/usr/bin/env bash para portabilidade, e o bloco de comentários com informações estruturadas. Também é útil incluir a data de última modificação e um histórico de versões.
Funções
Funções são blocos de código reutilizáveis que executam tarefas específicas. Em bash, funções são definidas com a sintaxe nome() { ... } ou function nome { ... }. Elas ajudam a evitar repetição, tornam o script mais modular e facilitam testes e manutenção.
Ao criar funções, siga boas práticas: use nomes descritivos (verbo + substantivo), mantenha funções curtas e com um propósito único, e documente cada função com um comentário explicando o que faz, parâmetros e retorno.
Exemplo de funções bem estruturadas:
#!/usr/bin/env bash
# Função para exibir ajuda
mostrar_ajuda() {
cat <<EOF
Uso: $(basename "$0") [opções]
Opções:
-h, --help Exibe esta ajuda
-v, --version Exibe a versão
EOF
}
# Função para verificar dependências
verificar_dependencias() {
local deps=("rsync" "tar")
for dep in "${deps[@]}"; do
if ! command -v "$dep" >/dev/null 2>&1; then
echo "Erro: dependência '$dep' não encontrada." >&2
exit 1
fi
done
}
# Função principal de backup
realizar_backup() {
local origem="$1"
local destino="$2"
echo "Iniciando backup de $origem para $destino..."
# ... lógica de backup ...
}
Note que usamos local para declarar variáveis dentro das funções, evitando poluir o escopo global. Também usamos command -v para verificar a existência de comandos.
main()
A função main() é uma convenção em muitas linguagens de programação para indicar o ponto de entrada do programa. Em bash, podemos criar uma função main() que organiza a execução principal do script, tornando o fluxo mais claro e facilitando a chamada de funções em ordem controlada.
Ter uma função main() também permite que o script seja executado como um módulo, pois podemos verificar se ele está sendo executado diretamente ou importado por outro script, usando ${BASH_SOURCE[0]} == "$0".
Estrutura típica:
#!/usr/bin/env bash
# Funções...
main() {
verificar_dependencias
# processar argumentos
# chamar funções específicas
realizar_backup "$@"
}
# Chamada da função principal apenas se o script for executado diretamente
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
main "$@"
fi
O teste if no final garante que, se o script for incluído em outro (via source), a função main() não seja executada automaticamente, permitindo reutilização das funções.
Constantes
Constantes são variáveis cujos valores não devem ser alterados durante a execução do script. Em bash, usamos readonly para declarar constantes. Elas são úteis para valores fixos como caminhos, configurações, mensagens padrão, etc.
Usar constantes melhora a legibilidade e evita erros de digitação, além de centralizar configurações em um único lugar. Convenção comum é usar nomes em MAIÚSCULAS com underscores.
Exemplo:
#!/usr/bin/env bash
# Constantes
readonly SCRIPT_NOME="$(basename "$0")"
readonly DIR_ORIGEM_PADRAO="/home/user/docs"
readonly DIR_DESTINO_PADRAO="/mnt/backup"
readonly LOG_FILE="/var/log/backup.log"
readonly VERSION="1.0.0"
# Uso das constantes
main() {
echo "Iniciando $SCRIPT_NOME versão $VERSION"
local origem="${1:-$DIR_ORIGEM_PADRAO}"
local destino="${2:-$DIR_DESTINO_PADRAO}"
# ...
}
Note o uso de ${1:-$DIR_ORIGEM_PADRAO} para usar o valor padrão caso o argumento não seja passado. Isso torna o script mais flexível.
Boas práticas e observações finais
Além dos tópicos abordados, algumas boas práticas ajudam a tornar seus scripts mais profissionais:
- Use
set -euo pipefailno início para sair em erros, evitar variáveis não definidas e capturar falhas em pipelines. - Trate os argumentos com
getoptsou bibliotecas comoargparse(em bash,getoptsé nativo). - Divida o script em arquivos menores se ele ficar muito grande, usando
sourcepara incluir bibliotecas. - Teste seu script com
shellcheckpara identificar problemas de sintaxe e boas práticas. - Adicione tratamento de erros com
trappara limpar recursos em caso de interrupção.
Lembre-se: um script profissional é aquele que pode ser mantido por outras pessoas sem dificuldade. Invista tempo na estrutura e documentação.
Exercícios
Crie um script bash que declare uma constante
NOME_EMPRESAcom valor "TechCorp" e uma funçãosaudacao()que imprima "Bem-vindo à $NOME_EMPRESA". Execute a função.✓ Resposta:#!/usr/bin/env bash readonly NOME_EMPRESA="TechCorp" saudacao() { echo "Bem-vindo à $NOME_EMPRESA" } saudacaoEscreva um script com uma função
main()que exiba a versão do script (constanteVERSAO= "1.0") e depois chame uma funçãoprocessar()que imprime "Processando...". O script deve executarmainapenas se for executado diretamente.✓ Resposta:#!/usr/bin/env bash readonly VERSAO="1.0" processar() { echo "Processando..." } main() { echo "Versão $VERSAO" processar } if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then main "$@" fiAdicione um cabeçalho completo ao script do exercício 2, incluindo descrição, autor, data e licença.
✓ Resposta:#!/usr/bin/env bash # # Script: exemplo.sh # Descrição: Script de exemplo com main() e constantes. # Autor: Seu Nome # Data: 2025-01-01 # Versão: 1.0 # Licença: MIT # Uso: ./exemplo.sh # readonly VERSAO="1.0" processar() { echo "Processando..." } main() { echo "Versão $VERSAO" processar } if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then main "$@" fiCrie um script que defina uma constante
DIR_DESTINOcom valor "/tmp/backup" e uma funçãocriar_diretorio()que verifica se o diretório existe e o cria se não existir. Usemkdir -p.✓ Resposta:#!/usr/bin/env bash readonly DIR_DESTINO="/tmp/backup" criar_diretorio() { if [[ ! -d "$DIR_DESTINO" ]]; then mkdir -p "$DIR_DESTINO" echo "Diretório $DIR_DESTINO criado." else echo "Diretório $DIR_DESTINO já existe." fi } criar_diretorioEscreva um script que use
set -euo pipefaile uma funçãosoma()que receba dois números e imprima a soma. O script deve chamarsomacom os números 3 e 5.✓ Resposta:#!/usr/bin/env bash set -euo pipefail soma() { local a="$1" local b="$2" echo $((a + b)) } soma 3 5