Boas práticas em shell
Esta aula aborda boas práticas em Shell Script, focando em quando evitar o shell, a importância de citar variáveis, o conceito de idempotência e os limites da linguagem. O conteúdo inclui exemplos práticos, exercícios com respostas e referências para aprofundamento.
Bem-vindo à aula 73 do nosso curso de Shell Script! Nesta aula, vamos explorar boas práticas essenciais para escrever scripts robustos, seguros e manuteníveis. Aprenderemos quando o shell é a ferramenta certa (e quando não é), como evitar armadilhas comuns com variáveis, o conceito de idempotência e os limites dessa linguagem poderosa, mas limitada.
O shell é uma ferramenta incrível para automação e tarefas de administração de sistemas, mas não é uma linguagem de propósito geral. Entender suas forças e fraquezas é crucial para se tornar um programador eficiente. Vamos mergulhar nas melhores práticas que separam scripts amadores de scripts profissionais.
Quando NÃO usar shell
O shell é excelente para tarefas que envolvem execução de comandos, manipulação de arquivos, pipelines e automação de processos. No entanto, existem situações em que o shell não é a melhor escolha. Por exemplo, quando você precisa de estruturas de dados complexas (como listas de dicionários), processamento intensivo de texto com expressões regulares avançadas, operações matemáticas de ponto flutuante, ou quando o desempenho é crítico, outras linguagens como Python, Perl ou Ruby podem ser mais adequadas.
Além disso, o shell não é ideal para desenvolvimento de aplicações grandes, com muitos módulos e testes unitários. A falta de tipagem, o escopo global de variáveis e a sintaxe propensa a erros tornam difícil manter código extenso. Se você está escrevendo mais de algumas centenas de linhas, considere usar uma linguagem de script mais estruturada.
Exemplo: Processar um arquivo CSV com muitos dados e cálculos numéricos é mais eficiente em Python:
# Em shell (difícil de manter)
while IFS=',' read -r nome idade; do
echo "$nome tem $idade anos"
done < dados.csv
# Em Python (mais claro e robusto)
import csv
with open('dados.csv') as f:
reader = csv.reader(f)
for nome, idade in reader:
print(f"{nome} tem {idade} anos")
Se você precisa de estruturas de dados como arrays associativos complexos, use Python. Se precisa de processamento de JSON, use jq (mas em scripts complexos, Python é melhor). Regra prática: se o script está ficando complexo, reescreva em uma linguagem de propósito geral.
Citando variáveis
Uma das práticas mais importantes em shell é citar variáveis. Sempre coloque aspas duplas ao redor das variáveis para evitar que o shell as expanda de forma inesperada. Isso previne a divisão de palavras e a expansão de globs (curingas). Por exemplo, se uma variável contém um espaço, sem aspas o comando pode quebrar.
Exemplo ruim:
nome="João Silva"
cp $nome /tmp/
# Isso vai tentar copiar os arquivos "João" e "Silva" separadamente
Exemplo bom:
nome="João Silva"
cp "$nome" /tmp/
# Isso copia o arquivo com espaço corretamente
Além de aspas duplas, use aspas simples quando não quiser nenhuma expansão. Por exemplo, para imprimir um literal com cifrão: echo 'O custo é $10'. Sempre cite argumentos que podem conter espaços ou caracteres especiais. Isso é especialmente crítico em scripts que processam nomes de arquivos com espaços.
Outra boa prática é usar ${var} em vez de $var quando a variável estiver concatenada com outros caracteres. Por exemplo: echo "${nome}_backup".
Idempotência
Idempotência significa que executar um script várias vezes produz o mesmo resultado que executá-lo uma vez. Isso é importante para scripts de automação, especialmente em deploys e configuração de sistemas. Um script idempotente não causa efeitos colaterais se for reexecutado. Por exemplo, se um script cria um diretório, ele deve verificar se o diretório já existe antes de tentar criar novamente.
Para tornar seus scripts idempotentes, use verificações antes de ações destrutivas. Por exemplo, antes de criar um usuário, verifique se ele já existe. Antes de adicionar uma linha a um arquivo, verifique se ela já está presente.
Exemplo: Criar um diretório de forma idempotente:
mkdir -p /tmp/meu_diretorio
# -p não dá erro se já existe, e cria diretórios intermediários
Outro exemplo: adicionar uma linha a um arquivo somente se ela não existir:
arquivo=/etc/hosts
linha="127.0.0.1 meuhost"
if ! grep -qF "$linha" "$arquivo"; then
echo "$linha" >> "$arquivo"
fi
Essa prática evita que a execução repetida de um script cause erros ou duplicações. Em sistemas de provisionamento como Ansible, a idempotência é um requisito fundamental.
Limites do shell
O shell tem várias limitações que devemos conhecer para evitar frustrações. Uma delas é a falta de suporte nativo a números de ponto flutuante. O shell só lida com inteiros. Para cálculos com decimais, você precisa usar ferramentas externas como bc ou awk.
Outra limitação é a ausência de arrays multidimensionais. O shell suporta arrays unidimensionais, mas não aninhados. Para estruturas de dados mais complexas, você precisa recorrer a strings ou arquivos temporários, o que é ineficiente.
Além disso, o shell não possui suporte a expressões regulares completas. Ele usa o básico com grep, sed e awk, mas não é tão poderoso quanto linguagens como Perl ou Python.
Exemplo de cálculo com ponto flutuante:
# Em shell, isso falha:
# echo $((10 / 3)) # resultado: 3 (inteiro)
# Use bc para precisão:
echo "scale=2; 10 / 3" | bc
# Saída: 3.33
Outra limitação é o desempenho: o shell é lento para loops grandes e processamento de texto. Para arquivos grandes, prefira ferramentas como awk ou sed que são otimizadas. Também é difícil depurar scripts complexos; use set -x para rastrear execução e shellcheck para análise estática.
Boas práticas adicionais
Aqui estão algumas dicas extras para melhorar seus scripts:
- Sempre comece seus scripts com
#!/bin/bashe useset -euo pipefailpara sair em erros, tratar variáveis não definidas e falhas em pipes. - Use funções para organizar código repetitivo.
- Documente seu script com comentários claros.
- Use nomes de variáveis em maiúsculas para variáveis de ambiente e minúsculas para locais.
- Teste seu script com
bash -npara verificar sintaxe eshellcheckpara boas práticas.
#!/bin/bash
set -euo pipefail
main() {
echo "Executando script..."
# ...
}
main "$@"
Referências
- Bash Reference Manual
- ShellCheck - Shell Script Analysis Tool
- Advanced Bash-Scripting Guide
- Bash Pitfalls
- GNU Coreutils Manual
- POSIX Shell Command Language
Exercícios
- Exercício 1: Escreva um script que copie um arquivo para um diretório de backup, mas que seja idempotente (não sobrescreva o arquivo se ele já existir). Use aspas corretamente.✓ Resposta:
#!/bin/bash origem="$1" destino="$2" if [[ ! -e "$destino" ]]; then cp "$origem" "$destino" echo "Copiado com sucesso." else echo "Arquivo já existe. Nada feito." fi - Exercício 2: Explique por que é importante citar variáveis em shell e dê um exemplo de erro que pode ocorrer sem aspas.✓ Resposta: Citamos variáveis para evitar que o shell as expanda de forma indesejada, como divisão de palavras e expansão de globs. Por exemplo, se uma variável contém um caminho com espaços, sem aspas o comando pode tentar executar em partes separadas, causando erros.
- Exercício 3: Liste duas situações em que você NÃO deveria usar shell e sugira uma linguagem alternativa.✓ Resposta: 1. Processamento intensivo de dados com estruturas complexas (use Python). 2. Aplicações web com lógica de negócio (use Node.js ou Ruby).
- Exercício 4: O que significa um script ser idempotente? Dê um exemplo de comando que é idempotente e um que não é.✓ Resposta: Idempotente:
mkdir -p /tmp/dir(não falha se já existe). Não idempotente:echo "linha" >> arquivo(adiciona linha repetidamente). - Exercício 5: Cite duas limitações do shell e como contorná-las.✓ Resposta: 1. Números de ponto flutuante: use
bcouawk. 2. Arrays multidimensionais: use strings ou arquivos temporários, ou mude para Python.
Observações finais
Dominar essas boas práticas elevará a qualidade dos seus scripts. Lembre-se sempre de citar variáveis, buscar idempotência, e avaliar se o shell é a ferramenta certa. Use ferramentas como ShellCheck para melhorar seus scripts e continue praticando!