Depurar scripts é uma habilidade fundamental para qualquer desenvolvedor que trabalhe com shell script. Erros de sintaxe, lógica ou variáveis não definidas podem causar comportamentos inesperados. Nesta aula, você aprenderá técnicas práticas para rastrear a execução do seu código, entender o que está acontecendo em cada etapa e encontrar bugs mais rapidamente.

Vamos explorar desde a execução com rastreamento (bash -x) até o uso de pontos de ativação/desativação do modo debug (set -x e set +x), logging personalizado e a ferramenta estática ShellCheck, que analisa seu código sem executá-lo.

bash -x

O modo mais simples e direto de depurar um script é executá-lo com a opção -x do Bash. Isso faz com que cada comando seja exibido no terminal antes de ser executado, precedido por um sinal de mais (+). As expansões de variáveis e substituições são mostradas, permitindo visualizar os valores reais sendo usados.

Por exemplo, considere o script soma.sh:

#!/bin/bash
a=10
b=20
soma=$((a + b))
echo "A soma é $soma"

Ao executar bash -x soma.sh, a saída será algo como:

+ a=10
+ b=20
+ soma=30
+ echo 'A soma é 30'
A soma é 30

Isso mostra exatamente o que o interpretador está fazendo. Se houver um erro, como uma variável não definida, o rastreamento ajuda a identificar onde o problema ocorre.

set -x e set +x

Em vez de depurar o script inteiro, você pode ativar e desativar o rastreamento em partes específicas usando set -x (ativar) e set +x (desativar). Isso é útil quando você quer focar apenas em uma seção problemática sem o ruído de todo o script.

Exemplo:

#!/bin/bash
echo "Início do script"
set -x
a=10
b=20
soma=$((a + b))
echo "Soma: $soma"
set +x
echo "Fim do script"

A saída será:

Início do script
+ a=10
+ b=20
+ soma=30
+ echo 'Soma: 30'
Soma: 30
Fim do script

Note que apenas os comandos entre set -x e set +x são rastreados. Você também pode usar set -v para exibir as linhas de entrada (antes da expansão) e set -xv para combinar ambos.

Logging

Adicionar mensagens de log ao seu script é uma prática essencial para depuração e manutenção. Em vez de depender apenas do rastreamento, você pode inserir instruções echo ou usar uma função de logging que exiba timestamps, níveis de severidade e informações contextuais.

Exemplo de função de logging simples:

#!/bin/bash

log() {
    local level="$1"
    local msg="$2"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $msg"
}

log "INFO" "Iniciando script"
a=10
log "DEBUG" "a = $a"
b=20
log "DEBUG" "b = $b"
soma=$((a + b))
log "INFO" "Soma calculada: $soma"
echo "Resultado: $soma"
log "INFO" "Script finalizado"

Você pode redirecionar a saída de log para um arquivo (exec >> logfile.log) ou para o stderr, e até usar níveis como DEBUG, INFO, WARN e ERROR. Isso facilita o monitoramento e a análise posterior.

shellcheck (visão geral)

ShellCheck é uma ferramenta de análise estática para scripts shell. Ela não executa o script, mas analisa o código fonte em busca de erros comuns, problemas de sintaxe, más práticas e possíveis bugs. É extremamente útil para detectar problemas antes mesmo de testar.

Para usar, instale via gerenciador de pacotes (ex.: apt install shellcheck no Ubuntu, brew install shellcheck no macOS) e execute:

shellcheck seu_script.sh

Exemplo de saída:

In seu_script.sh line 6:
echo "A soma é $soma"
^-- SC2148: Tips depend on target shell and yours is unknown. Add shebang.
                 ^-- SC2086: Double quote to prevent globbing and word splitting.

Cada aviso tem um código (ex.: SC2086) que remete a uma página de documentação explicando o problema e como corrigi-lo. Integrar ShellCheck ao seu editor (VS Code, Vim, etc.) permite feedback em tempo real enquanto você escreve o script.

Boas práticas e observações finais

Combine as técnicas: use bash -x para uma visão geral, set -x/set +x para isolar trechos, logging para ter um histórico e ShellCheck para prevenir erros. Sempre teste scripts em um ambiente seguro antes de colocar em produção. Lembre-se de que depuração é um processo iterativo; quanto mais cedo você detectar um erro, mais fácil corrigi-lo.

Referências

Exercícios

  1. Considere o script abaixo. Execute-o com bash -x e explique o que cada linha do rastreamento significa.

    #!/bin/bash
    nome="Alice"
    echo "Olá, $nome"
    idade=25
    echo "Idade: $idade"

    ✓ Resposta: A saída será algo como:
    + nome=Alice
    + echo 'Olá, Alice'
    Olá, Alice
    + idade=25
    + echo 'Idade: 25'
    Idade: 25
    Cada linha iniciada com '+' mostra o comando após a expansão de variáveis. A linha + nome=Alice indica a atribuição da variável. + echo 'Olá, Alice' mostra o comando echo com a variável já expandida. As linhas seguintes seguem o mesmo padrão.
  2. Modifique o script do exercício 1 para que apenas a parte que exibe a idade seja rastreada usando set -x e set +x. Escreva o script modificado.

    ✓ Resposta:
    #!/bin/bash
    nome="Alice"
    echo "Olá, $nome"
    set -x
    idade=25
    echo "Idade: $idade"
    set +x
    Ao executar, apenas as linhas entre set -x e set +x serão rastreadas.
  3. Crie uma função de logging que escreva mensagens com timestamp e nível (INFO, DEBUG, ERROR) em um arquivo script.log. Use-a em um script simples que define duas variáveis e as exibe.

    ✓ Resposta:
    #!/bin/bash
    
    log() {
        local level="$1"
        local msg="$2"
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $msg" >> script.log
    }
    
    log "INFO" "Início do script"
    a=10
    log "DEBUG" "a = $a"
    b=20
    log "DEBUG" "b = $b"
    echo "a=$a, b=$b"
    log "INFO" "Fim do script"
    Execute e verifique o conteúdo de script.log.
  4. Execute o ShellCheck no script abaixo e liste pelo menos dois avisos que ele emitiria (não precisa corrigir).

    #!/bin/bash
    nome="João"
    echo "Olá, $nome"
    for i in 1 2 3; do
    echo $i
    done

    ✓ Resposta: ShellCheck provavelmente emitiria:
    • SC2086: Double quote to prevent globbing and word splitting (na linha echo $i).
    • SC2034: 'nome' appears unused (se a variável não for usada depois).
    • SC2148: Tips depend on target shell and yours is unknown. Add shebang. (já tem shebang, mas pode reclamar se não estiver na primeira linha).
  5. Escreva um script que contenha um erro proposital (ex.: variável não definida ou comando digitado errado). Use bash -x para encontrar o erro e descreva como o rastreamento ajudou.

    ✓ Resposta: Exemplo de script com erro:
    #!/bin/bash
    echo "Calculando..."
    resultado=$((10 / 0))
    echo "Resultado: $resultado"
    Ao executar com bash -x, a saída mostra:
    + echo 'Calculando...'
    Calculando...
    + resultado=10 / 0
    bash: line 4: 10 / 0: division by 0 (error token is "0 ")
    O rastreamento mostra exatamente onde a divisão por zero ocorre, indicando a linha e o erro. Isso permite corrigir rapidamente.