Análise estática com ShellCheck
Nesta aula, você aprenderá a usar o ShellCheck, uma ferramenta de análise estática para scripts Bash, que detecta erros, más práticas e possíveis bugs antes da execução. Vamos explorar o que ele detecta, os avisos mais comuns, como integrá-lo ao seu fluxo de trabalho e boas práticas para escrever scripts mais robustos.
Bem-vindo à aula 71! Até agora, você aprendeu a escrever scripts Bash funcionais, mas escrever código que funciona é apenas o começo. Em projetos reais, especialmente quando os scripts crescem em complexidade, erros sutis podem passar despercebidos e causar falhas em produção. É aqui que entra a análise estática: uma técnica que examina o código sem executá-lo, procurando por padrões problemáticos, bugs potenciais e más práticas.
Nesta aula, vamos focar no ShellCheck, a ferramenta padrão de análise estática para scripts shell. Você vai entender o que ela detecta, quais são os avisos mais comuns, como integrá-la em seu ambiente de desenvolvimento e como usá-la para melhorar a qualidade dos seus scripts. Ao final, você terá um conjunto de boas práticas que elevará seus scripts a um nível profissional.
O que detecta
O ShellCheck é um analisador estático que examina scripts shell (principalmente Bash, mas também POSIX sh, Dash, Ksh, entre outros) e emite avisos e erros sobre problemas potenciais. Ele não executa o script, mas sim analisa a sintaxe e a semântica, procurando por armadilhas comuns que podem levar a comportamentos inesperados, falhas de segurança ou simplesmente código confuso.
Os problemas detectados podem ser classificados em várias categorias:
- Erros de sintaxe: comandos mal formados, parênteses desbalanceados, aspas não fechadas, etc.
- Problemas de portabilidade: uso de recursos que não estão disponíveis em todas as shells (ex.:
[[ ]]não é POSIX). - Armadilhas de expansão: uso incorreto de variáveis, falta de aspas em expansões que podem quebrar.
- Problemas de segurança: uso inseguro de
eval, caminhos não sanitizados, etc. - Más práticas: uso de comandos obsoletos, falta de tratamento de erros, etc.
Por exemplo, considere o script abaixo:
#!/bin/bash
# script com problemas
nome=$1
if [ $nome == "joao" ]
then
echo "Olá, João"
fi
O ShellCheck detectaria vários problemas: a variável $nome não está entre aspas (o que pode causar erros se contiver espaços), o uso de == dentro de [ ] não é POSIX (deveria ser =), e a variável $1 pode não estar definida. Vamos ver isso em ação mais adiante.
O ShellCheck é extremamente útil para encontrar bugs antes que eles aconteçam. Ele é usado em muitos projetos open source e é uma ferramenta padrão em pipelines de CI (Integração Contínua) para garantir a qualidade dos scripts.
Avisos comuns
O ShellCheck emite avisos com códigos numéricos, que variam de 1000 a 2999. Cada código indica um tipo específico de problema. Vamos explorar os avisos mais comuns que você encontrará:
- SC2086: "Double quote to prevent globbing and word splitting." — Este é um dos avisos mais frequentes. Ocorre quando você usa uma variável sem aspas, como
echo $var. O ShellCheck recomenda usar"$var"para evitar que o valor seja dividido em palavras ou interpretado como padrão de globbing. - SC2164: "Use 'cd ... || exit' or 'cd ... || return' in case cd fails." — Quando você usa
cdem um script, se o diretório não existir, o script continua executando em um diretório errado. O ShellCheck sugere tratar o erro imediatamente. - SC2002: "Useless cat. Consider 'cmd < file' or 'cmd file' instead." — O uso de
cat arquivo | comandoé desnecessário; você pode redirecionar diretamente. - SC2034: "Var appears unused. Verify it or export it." — Uma variável foi definida, mas nunca usada. Isso pode indicar um erro de digitação ou código morto.
- SC2016: "Expressions don't expand in single quotes, use double quotes for that." — Ocorre quando você usa aspas simples em uma string que contém
$e espera expansão.
Vamos ver um exemplo prático que gera vários avisos:
#!/bin/bash
# exemplo com problemas
for arquivo in $(ls *.txt)
do
echo "Processando $arquivo"
cat $arquivo | grep "erro"
done
Ao rodar o ShellCheck, você obteria:
$ shellcheck exemplo.sh
In exemplo.sh line 2:
for arquivo in $(ls *.txt)
^-- SC2045: Iterating over ls output is fragile. Use globs.
In exemplo.sh line 4:
echo "Processando $arquivo"
^-- SC2086: Double quote to prevent globbing and word splitting.
In exemplo.sh line 5:
cat $arquivo | grep "erro"
^-- SC2086: Double quote to prevent globbing and word splitting.
^-- SC2002: Useless cat. Consider 'cmd < file' or 'cmd file' instead.
O ShellCheck não apenas aponta o problema, mas também sugere a correção. Você pode usar a opção -f para formatar a saída de várias maneiras, como JSON, TAP, etc.
Integração
O ShellCheck pode ser integrado de várias maneiras no seu fluxo de trabalho. Aqui estão as principais:
Linha de comando
O uso mais básico é executar o ShellCheck em um arquivo:
shellcheck meu_script.sh
Para ver a saída em formato JSON (útil para ferramentas):
shellcheck -f json meu_script.sh
Você também pode especificar o shell alvo com -s (ex.: -s dash).
Editores de texto e IDEs
O ShellCheck é integrado a muitos editores populares:
- VS Code: instale a extensão "ShellCheck" da Microsoft.
- Vim: use o plugin
aleousyntastic. - Emacs: use
flycheckcom o suporte a ShellCheck. - Sublime Text: instale o pacote "SublimeLinter-shellcheck".
Essas integrações exibem avisos em tempo real enquanto você digita, o que ajuda a corrigir problemas imediatamente.
CI/CD
Em pipelines de integração contínua, você pode executar o ShellCheck como uma etapa de verificação. Por exemplo, em um GitHub Action:
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: './scripts'
Ou em um script Jenkins:
shellcheck scripts/*.sh
Isso garante que nenhum script com problemas seja mesclado no repositório.
Pré-commit
Você pode usar o pre-commit para rodar o ShellCheck antes de cada commit. Adicione ao seu arquivo .pre-commit-config.yaml:
repos:
- repo: https://github.com/koalaman/shellcheck-precommit
rev: v0.9.0
hooks:
- id: shellcheck
Boas práticas
Aqui estão algumas boas práticas para aproveitar ao máximo o ShellCheck e melhorar a qualidade dos seus scripts:
- Sempre use aspas duplas em variáveis: a menos que você queira intencionalmente a divisão de palavras (o que é raro), use
"$var". - Evite
lsem loops: use globs (*.txt) em vez defor arquivo in $(ls *.txt). - Trate erros de
cd: usecd diretorio || exitpara evitar continuar no diretório errado. - Prefira
[[ ]]em Bash: se você está escrevendo para Bash, use[[ ]]em vez de[ ], pois é mais seguro e poderoso. - Seja explícito com o shebang: declare
#!/bin/bashou#!/usr/bin/env bashpara que o ShellCheck saiba qual shell usar. - Use
set -eouset -o pipefailcom cuidado: o ShellCheck pode ajudar a identificar onde esses comandos podem causar problemas. - Revise os avisos, não apenas os ignore: cada aviso é uma oportunidade de aprender e melhorar.
Um exemplo de script corrigido com base nos avisos:
#!/bin/bash
# exemplo corrigido
for arquivo in *.txt
do
echo "Processando $arquivo"
grep "erro" "$arquivo" || echo "Nenhum erro encontrado"
done
Ao rodar o ShellCheck novamente, nenhum aviso será emitido.
Referências
- ShellCheck no GitHub
- Site oficial do ShellCheck
- Wiki do ShellCheck - SC2086
- Manual do Bash
- Advanced Bash-Scripting Guide
- Bash Hackers Wiki
Exercícios
- Instale o ShellCheck no seu sistema (se ainda não estiver instalado) e verifique a versão. Qual comando você usou?
- O que o aviso SC2086 indica e como corrigi-lo? Dê um exemplo.
- Crie um script Bash que contenha pelo menos três problemas que o ShellCheck detectaria (por exemplo, uso de
lsem loop, variável sem aspas,catdesnecessário). Execute o ShellCheck e liste os avisos. - Como você integraria o ShellCheck em um pipeline de CI usando GitHub Actions? Escreva o trecho do YAML.
- Explique a diferença entre
[ ]e[[ ]]no Bash e por que o ShellCheck recomenda[[ ]]para scripts Bash.
sudo apt install shellcheck (no Debian/Ubuntu) ou brew install shellcheck (no macOS). Para verificar: shellcheck --version.echo $nome → echo "$nome".#!/bin/bash
for arq in $(ls *.txt)
do
cat $arq | grep "x"
done Avisos: SC2045 (ls em loop), SC2086 (variável sem aspas), SC2002 (cat desnecessário).- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: './scripts'[ ] é o comando test, POSIX, que tem limitações (ex.: não suporta regex, precisa de aspas em variáveis). [[ ]] é uma palavra-chave do Bash que é mais segura e poderosa (suporta regex, operadores && e || sem aspas). O ShellCheck recomenda [[ ]] porque é mais robusto e evita erros comuns.Considerações finais
O ShellCheck é uma ferramenta indispensável para qualquer desenvolvedor que trabalhe com shell scripting. Ele não apenas ajuda a evitar bugs, mas também ensina boas práticas através de seus avisos. Ao incorporá-lo no seu fluxo de trabalho, você escreverá scripts mais confiáveis, seguros e portáveis. Lembre-se de que a análise estática é uma camada de proteção, mas não substitui testes e revisões de código. Use o ShellCheck como parte de uma estratégia mais ampla de qualidade de software.