Documentation de scripts: comentários e --help

1. Por que documentar scripts Bash?

1.1. Manutenibilidade: facilitando a compreensão do código por outros (e pelo seu "eu" do futuro)

Todo desenvolvedor já passou pela situação de revisitar um script próprio meses depois e não entender o que cada bloco faz. A documentação adequada transforma scripts enigmáticos em ferramentas compreensíveis. Comentários estratégicos reduzem o tempo de manutenção em até 50% e previnem a introdução de bugs quando alterações são necessárias.

1.2. Colaboração: scripts como parte de um repositório compartilhado

Em ambientes corporativos ou projetos open source, scripts Bash frequentemente compõem pipelines de CI/CD, automações de infraestrutura ou tarefas de desenvolvimento. Sem documentação clara, a colaboração se torna um exercício de adivinhação. Um script bem documentado permite que qualquer membro da equipe entenda rapidamente o propósito, as dependências e o modo de uso.

1.3. Padronização: documentação como parte do fluxo de qualidade

Assim como linting (ShellCheck) e testes (Bats), a documentação deve ser parte integrante do fluxo de qualidade. Times que adotam templates padronizados de cabeçalho e implementam a flag --help reduzem drasticamente o retrabalho e facilitam a revisão de código.


2. Comentários no código: boas práticas e níveis de detalhamento

2.1. Comentários de cabeçalho: autor, descrição, dependências e versão

O cabeçalho é a identidade do script. Deve conter informações essenciais que qualquer pessoa precisa saber antes de executá-lo.

#!/bin/bash
#
# Script: backup_db.sh
# Descrição: Realiza backup completo do banco PostgreSQL e compacta o resultado
# Autor: Maria Silva <maria@exemplo.com>
# Versão: 2.1.0
# Licença: MIT
# Dependências: pg_dump (PostgreSQL client), gzip, aws-cli
# Uso: ./backup_db.sh [opções]

2.2. Comentários inline: quando explicar o "porquê" e não o "como"

Comentários inline devem explicar a intenção por trás de decisões não óbvias, não o funcionamento básico da linguagem.

# Ruim: explica o óbvio
# Incrementa a variável contador em 1
contador=$((contador + 1))

# Bom: explica o motivo
# Usamos sleep de 5 segundos para evitar rate limit da API
sleep 5

2.3. Comentários de seção: dividindo o script em blocos lógicos

Organizar o script em seções claras facilita a navegação e a manutenção.

# ============================================================
# SEÇÃO: Configurações e variáveis globais
# ============================================================

# ============================================================
# SEÇÃO: Funções utilitárias
# ============================================================

# ============================================================
# SEÇÃO: Validação de argumentos
# ============================================================

# ============================================================
# SEÇÃO: Execução principal
# ============================================================

3. Estrutura de um comentário de cabeçalho padrão

3.1. Metadados essenciais

Um cabeçalho completo deve incluir:

#!/bin/bash
#
# Nome do script
# Descrição funcional (o que faz, não como faz)
# Autor e contato
# Versão semântica (X.Y.Z)
# Licença de uso
# Data de criação e última modificação

3.2. Documentação de dependências

Liste explicitamente ferramentas externas e versões mínimas quando aplicável:

# Dependências:
#   - curl >= 7.68.0
#   - jq >= 1.6
#   - openssl >= 1.1.1

3.3. Exemplo prático: template de cabeçalho reutilizável

#!/bin/bash
#
# Script:     <nome_do_script>.sh
# Descrição:  <breve descrição funcional>
# Autor:      <nome> <<email>>
# Versão:     <X.Y.Z>
# Licença:    <tipo>
# Criado em:  <data>
# Modificado: <data>
# Uso:        ./<script>.sh [opções] <argumentos>
# Exemplo:    ./<script>.sh -v -o saida.txt entrada.txt
# Dependências:
#   - <ferramenta1> (>= versão)
#   - <ferramenta2>

4. Implementando a flag --help (ou -h)

4.1. Estrutura básica com função usage()

A função usage() deve ser chamada sempre que o usuário solicitar ajuda ou fornecer argumentos inválidos.

#!/bin/bash

usage() {
    cat << EOF
Uso: $(basename "$0") [OPÇÕES] <arquivo>

Processa arquivos de log e gera relatório resumido.

OPÇÕES:
    -h, --help        Exibe esta mensagem de ajuda
    -v, --verbose     Modo detalhado de execução
    -o, --output ARQ  Define arquivo de saída (padrão: relatorio.txt)
    -f, --format FMT  Formato do relatório: txt, csv, json (padrão: txt)

EXEMPLOS:
    $(basename "$0") acesso.log
    $(basename "$0") -v -o relatorio.csv -f csv acesso.log

REPORTE BUGS PARA: <email>
$(basename "$0") versão 1.0.0
EOF
    exit 0
}

4.2. Integração com getopts

while getopts ":hvo:f:" opt; do
    case $opt in
        h) usage ;;
        v) VERBOSE=true ;;
        o) OUTPUT="$OPTARG" ;;
        f) FORMAT="$OPTARG" ;;
        \?) echo "Opção inválida: -$OPTARG" >&2; usage ;;
        :) echo "Opção -$OPTARG requer argumento" >&2; usage ;;
    esac
done

4.3. Tratamento de erros com exibição do help

if [ $# -eq 0 ]; then
    echo "Erro: Nenhum argumento fornecido." >&2
    usage
fi

if [ ! -f "$1" ]; then
    echo "Erro: Arquivo '$1' não encontrado." >&2
    usage
fi

5. Formatando a saída do --help para legibilidade

5.1. Uso de cat <<EOF vs echo vs printf

  • cat <<EOF: Ideal para blocos de texto multilinha com formatação consistente
  • echo: Adequado para linhas simples, mas limita formatação
  • printf: Oferece controle preciso sobre formatação, útil para tabelas
# Preferido para help completo
cat << EOF
Uso: $(basename "$0") [OPÇÕES] <arquivo>
...
EOF

# Alternativa com printf para formatação tabular
printf "  %-20s %s\n" "-h, --help" "Exibe ajuda"
printf "  %-20s %s\n" "-v, --verbose" "Modo detalhado"

5.2. Indentação, quebras de linha e colunas organizadas

Mantenha alinhamento consistente usando espaços ou tabs, e limite linhas a 80 caracteres para legibilidade em terminais.

5.3. Cores e formatação ANSI

Use cores com moderação e apenas quando a saída não for redirecionada:

if [ -t 1 ]; then
    GREEN='\033[0;32m'
    NC='\033[0m' # No Color
    echo -e "${GREEN}OK${NC}: Operação concluída"
else
    echo "OK: Operação concluída"
fi

6. Manutenção da documentação: sincronia com o código

6.1. Versionamento da documentação junto com o script

Sempre atualize cabeçalho e help no mesmo commit que altera a lógica do script. Use revisão de código para verificar se a documentação reflete as mudanças.

6.2. Scripts de auto-documentação

Ferramentas como help2man podem extrair comentários formatados e gerar páginas man automaticamente:

# Instalação: apt-get install help2man
help2man -N ./meu_script.sh > meu_script.1

6.3. Ferramentas auxiliares

  • argbash: Gera scripts com parsing de argumentos e help a partir de um template
  • docopt.sh: Implementa interface docopt para Bash
  • shflags: Biblioteca para parsing de flags com help automático

7. Estendendo a documentação: man pages e README

7.1. Gerando páginas de manual (man)

Com help2man e um cabeçalho bem estruturado, é possível gerar páginas man completas:

# No script, inclua seções formatadas para man:
# .TH MEU_SCRIPT 1 "2024-01-15" "1.0.0" "Ferramentas de Sistema"
# .SH NOME
# meu_script \- processa arquivos de log

7.2. README.md como complemento

O README deve conter exemplos de instalação, dependências, casos de uso avançados e links para documentação adicional.

7.3. Integração com sistemas de distribuição

Em projetos com Makefile, inclua targets para instalação da documentação:

install-docs:
    cp meu_script.1 /usr/local/share/man/man1/
    mandb

8. Exemplo completo e checklist final

8.1. Script comentado do início ao fim

#!/bin/bash
#
# Script:     log_processor.sh
# Descrição:  Processa arquivos de log e gera relatórios em múltiplos formatos
# Autor:      João Santos <joao@exemplo.com>
# Versão:     1.2.0
# Licença:    MIT
# Criado em:  2024-01-15
# Uso:        ./log_processor.sh [opções] <arquivo_log>
# Dependências:
#   - grep (qualquer versão)
#   - awk (qualquer versão)

# ============================================================
# CONFIGURAÇÕES
# ============================================================
VERBOSE=false
OUTPUT="relatorio.txt"
FORMAT="txt"

# ============================================================
# FUNÇÃO DE AJUDA
# ============================================================
usage() {
    cat << EOF
Uso: $(basename "$0") [OPÇÕES] <arquivo_log>

Processa arquivos de log e gera relatório resumido.

OPÇÕES:
    -h, --help        Exibe esta mensagem de ajuda
    -v, --verbose     Modo detalhado de execução
    -o, --output ARQ  Define arquivo de saída (padrão: relatorio.txt)
    -f, --format FMT  Formato do relatório: txt, csv, json (padrão: txt)

EXEMPLOS:
    $(basename "$0") acesso.log
    $(basename "$0") -v -o relatorio.csv -f csv acesso.log

REPORTE BUGS PARA: joao@exemplo.com
$(basename "$0") versão 1.2.0
EOF
    exit 0
}

# ============================================================
# PARSING DE ARGUMENTOS
# ============================================================
while getopts ":hvo:f:" opt; do
    case $opt in
        h) usage ;;
        v) VERBOSE=true ;;
        o) OUTPUT="$OPTARG" ;;
        f) FORMAT="$OPTARG" ;;
        \?) echo "Opção inválida: -$OPTARG" >&2; usage ;;
        :) echo "Opção -$OPTARG requer argumento" >&2; usage ;;
    esac
done
shift $((OPTIND - 1))

# ============================================================
# VALIDAÇÕES
# ============================================================
if [ $# -eq 0 ]; then
    echo "Erro: Nenhum arquivo de log especificado." >&2
    usage
fi

LOG_FILE="$1"

if [ ! -f "$LOG_FILE" ]; then
    echo "Erro: Arquivo '$LOG_FILE' não encontrado." >&2
    exit 1
fi

# ============================================================
# EXECUÇÃO PRINCIPAL
# ============================================================
[ "$VERBOSE" = true ] && echo "Processando $LOG_FILE..."

# Conta ocorrências de erro
ERROR_COUNT=$(grep -ci "ERROR" "$LOG_FILE")
[ "$VERBOSE" = true ] && echo "Erros encontrados: $ERROR_COUNT"

# Gera relatório conforme formato
case $FORMAT in
    txt) echo "Total de erros: $ERROR_COUNT" > "$OUTPUT" ;;
    csv) echo "metric,value\nerrors,$ERROR_COUNT" > "$OUTPUT" ;;
    json) echo "{\"errors\": $ERROR_COUNT}" > "$OUTPUT" ;;
esac

echo "Relatório gerado: $OUTPUT"

8.2. Checklist de verificação

  • [ ] Cabeçalho completo (nome, descrição, autor, versão, licença, dependências)
  • [ ] Função usage() implementada e chamada por -h e --help
  • [ ] Tratamento de argumentos inválidos com exibição do help
  • [ ] Exemplos de uso no help
  • [ ] Comentários de seção organizando o código
  • [ ] Comentários inline explicando decisões não óbvias
  • [ ] Saída do help legível e bem formatada
  • [ ] Testes básicos realizados (ShellCheck, execução com -h)

8.3. Checklist para colaboração

  • [ ] Script validado com ShellCheck
  • [ ] README.md atualizado com exemplos de uso
  • [ ] Página man gerada (se aplicável)
  • [ ] Dependências documentadas e verificáveis

Referências