Dominando a Depuração de Scripts Bash: Técnicas Essenciais para Desenvolvedores
Depure scripts Bash com verificações de sintaxe, xtrace, modo estrito, traps, ShellCheck e registro focado.
Dominando a Depuração de Scripts Bash: Técnicas Essenciais para Desenvolvedores
A depuração de scripts Bash começa com uma pergunta: onde o script fez algo diferente do que você esperava? Uma boa depuração oferece visibilidade sobre erros de sintaxe, variáveis expandidas, ordem de comandos e status de saída sem transformar o script em ruído.
Este guia aborda técnicas práticas de depuração Bash que você pode usar em um script de automação real antes de ele chegar ao cron, CI ou produção.
Comece com uma Verificação de Sintaxe
Antes de rastrear o comportamento em tempo de execução, certifique-se de que o Bash pode analisar o arquivo:
bash -n ./deploy.sh
bash -n lê o script e relata erros de sintaxe sem executar comandos. Ele detecta fi, done, then, aspas e chaves ausentes. Não detectará erros de lógica, arquivos ausentes ou comandos que falham em tempo de execução.
Por exemplo, este erro de digitação é detectado antes de qualquer coisa ser executada:
if [ -f "$CONFIG" ]; then
echo "Config encontrada"
# fi ausente
Execute uma verificação de sintaxe após grandes edições e antes de adicionar mais saída de depuração.
Rastreie a Execução com set -x
O depurador embutido mais útil é o xtrace:
set -x
algum_comando "$VALOR"
set +x
Com o rastreamento ativado, o Bash imprime cada comando após as expansões e antes da execução. Isso ajuda a ver se uma variável está vazia, se um glob foi expandido ou se um comando recebeu argumentos diferentes do esperado.
Para rastreamento de script inteiro, execute:
bash -x ./deploy.sh
Para rastreamentos mais limpos, defina PS4 para que cada linha inclua o número da linha de origem:
export PS4='+ ${BASH_SOURCE}:${LINENO}: '
bash -x ./deploy.sh
Se o seu script lida com segredos, não rastreie seções que imprimem tokens, senhas ou URLs assinadas. Desative o rastreamento antes desses comandos:
set +x
login_com_segredo "$API_TOKEN"
set -x
Adicione o Modo Estrito com Cuidado
Estas opções detectam falhas comuns mais cedo:
set -euo pipefail
set -e sai em muitas falhas de comando não tratadas. set -u trata variáveis não definidas como erros. set -o pipefail faz com que um pipeline falhe se qualquer comando no pipeline falhar, não apenas o último comando.
Elas são úteis, mas não substituem o tratamento explícito. Comandos como grep podem retornar 1 para um resultado normal de "não encontrado":
if grep -q "PRONTO" status.txt; then
echo "pronto"
else
echo "não pronto"
fi
Isso é mais claro do que esconder o resultado com grep -q "PRONTO" status.txt || true.
Imprima os Valores Corretos
Registro focado supera linhas echo espalhadas. Imprima os valores que afetam o ramo que você está depurando:
printf 'DEBUG: usuario=%q ambiente=%q alvo=%q\n' "$NOME_USUARIO" "$AMBIENTE" "$HOST_ALVO" >&2
printf '%q' mostra valores escapados pelo shell, o que facilita a identificação de espaços e caracteres especiais. Envie a saída de depuração para stderr para que a saída normal do script permaneça utilizável em pipelines.
Quando um comando falha, capture seu status imediatamente:
executar_migracao
status=$?
if [ "$status" -ne 0 ]; then
echo "Migração falhou com código de saída $status" >&2
exit "$status"
fi
Não execute outro comando antes de salvar $?, porque até mesmo echo o substitui.
Depure Loops e Condicionais
Bugs em loops geralmente vêm de divisão de palavras ou entrada inesperada. Coloque variáveis entre aspas e leia linhas com segurança:
while IFS= read -r linha; do
printf 'linha=%q\n' "$linha" >&2
done < input.txt
Para condicionais, imprima os valores exatos sendo comparados:
printf 'esperado=%q real=%q\n' "$ESPERADO" "$REAL" >&2
if [[ "$REAL" == "$ESPERADO" ]]; then
echo "correspondência"
fi
Se você precisar pausar dentro de um script durante a depuração local, read funciona:
read -r -p "Pressione Enter para continuar..."
Remova as pausas antes de confirmar o script, especialmente se ele puder ser executado sem supervisão.
Use ShellCheck para Análise Estática
O ShellCheck detecta muitos problemas que o Bash executará felizmente até que eles quebrem em um caso extremo:
shellcheck ./deploy.sh
Ele sinaliza variáveis sem aspas, código inacessível, testes suspeitos, variáveis não utilizadas e problemas de portabilidade. Trate os avisos como prompts para inspecionar o código, não como prova automática de que o script está errado. Às vezes, você pode desabilitar intencionalmente um aviso, mas adicione um breve comentário explicando o porquê.
Use trap para Ver a Linha com Falha
Para scripts mais longos, um trap de erro pode informar onde ocorreu uma falha:
set -Eeo pipefail
trap 'echo "Erro na linha $LINENO: $BASH_COMMAND" >&2' ERR
set -E ajuda o trap ERR a se propagar para funções e subshells no Bash. Isso é útil em logs de CI onde você pode não ter um shell interativo.
Conclusão
Comece com bash -n, use bash -x ou set -x direcionado para rastreamento em tempo de execução e adicione registro focado em stderr ao redor do ramo que se comporta incorretamente. Para scripts importantes, execute o ShellCheck e adicione um trap ERR para que as falhas apontem para o comando e a linha que precisam de atenção.