O Bash é como um canivete suíço: simples, omnipresente e perigoso se não souberes o que estás a fazer. Já perdi horas a debuggar scripts que correram em produção com variáveis vazias. Depois de set -euo pipefail, nunca mais.
Durante anos, os meus scripts Bash eram um monstro: funcionavam no meu Mac, partiam no servidor, e quando algo corria mal, o script continuava feliz como se nada tivesse acontecido. Até que um dia um rm -rf com uma variável vazia quase me custou um servidor inteiro.
Foi aí que percebi que escrever Bash não é só colar comandos. É uma arte de disciplina: error handling, quoting consistente, funções bem definidas, e ferramentas como o shellcheck que te salvam de ti próprio.
Vou mostrar-te:
- Error handling a sério com set -euo pipefail e trap
- Debugging como um profissional
- Subshells, funções e argument parsing
- Boas práticas: quoting, [[ ]], variáveis com fallback
- O essencial do shellcheck e profiles
⬆ Script Bash a correr com debugging ativo (set -x) e cores de output
Error handling: o teu salva-vidas
Por omissão, o Bash não para quando um comando falha. Isto é aterrador. Se fizeres cd /diretorio-que-nao-existe && rm -rf ., o Bash queixa-se do cd mas faz o rm na mesma no diretório atual. Já viste o perigo?
Cada letra tem um propósito:
| Flag | O que faz | Exemplo |
|---|---|---|
| -e | Sai logo se um comando falhar (exit code ≠ 0) | cd /x || exit 1 |
| -u | Erro ao usar variável não definida | echo $NAO_EXISTO → erro |
| -o pipefail | Se um comando no pipe falhar, o pipe todo falha | grep foo /x | sort → falha se grep falhar |
Mas há cenários onde queres ignorar erros específicos. Usa || true para isso:
trap: o paraquedas de emergência
O trap permite-te executar código quando o script recebe sinais ou termina. Uso essencial: limpar ficheiros temporários:
Dica: Usa trap 'comando' EXIT para garantires que a limpeza corre sempre, mesmo que o script rebente a meio. O trap ERR é utilíssimo para logging de erros.
Debugging: set -x e amigos
Quando um script não faz o que queres, o set -x é o teu melhor amigo. Ele mostra cada comando antes de executar, com expansão de variáveis:
Outras técnicas de debugging:
- bash -n script.sh: verifica sintaxe sem executar (linter básico)
- export SHELLOPTS: passa opções para sub-shells
- PS4='+ $BASH_SOURCE:$LINENO ': personaliza o output do set -x com ficheiro e linha
Subshells: $() vs ( ) vs { }
Esta é uma das maiores fontes de confusão no Bash. Vamos clarificar:
| Sintaxe | Tipo | Comportamento |
|---|---|---|
| $(comando) | Substituição de comando | Corre o comando e devolve o output. Não cria subshell pai |
| (comandos) | Subshell | Corre comandos num shell filho. Variáveis não afetam o pai |
| { comandos; } | Grouping | Corre no mesmo shell. Mais eficiente. Espaços obrigatórios |
Exemplo prático para perceberes a diferença:
Atenção: Usa { } em vez de ( ) sempre que não precisares de isolamento. É mais rápido e consome menos memória. Em loops com milhares de iterações, a diferença é notória.
Funções: local, return e argumentos
Funções em Bash são o equivalente a organização. Sem elas, os teus scripts são uma sopa de comandos. Com funções bem desenhadas, são programas.
Regras de ouro para funções:
- Sempre local nas variáveis: não poluas o scope global
- return apenas para código de erro (0-255). Para devolver dados, usa echo ou variáveis globais
- Argumentos: $1, $2, ... $@ para todos, $# para contagem
- Valida sempre os argumentos no início da função
Boas práticas essenciais
Ao longo dos anos, cristalizei um conjunto de regras que todo o script Bash devia seguir:
Quoting: sempre que há espaços
[[ ]] vs [ ]: a batalha dos tests
| [ ] (POSIX) | [[ ]] (Bash) |
|---|---|
| Disponível em qualquer shell POSIX | Apenas Bash/Zsh/Ksh |
| Não suporta &&, || dentro | Suporta &&, ||, ! naturalmente |
| Precisa de quoting para variáveis vazias | Lida com strings vazias sem problemas |
| Sem suporte para regex | =~ para regex nativo |
Variáveis com valores por omissão
Variáveis readonly e constantes
Ferramentas que te salvam a vida
| Ferramenta | O que faz |
|---|---|
| shellcheck | Linter para Bash: deteta quoting errors, variáveis não usadas, problemas de sintaxe. Instala com brew install shellcheck ou apt install shellcheck |
| bash -n | Verifica sintaxe sem executar: rápido para CI/CD |
| shfmt | Formatador automático de Bash: indenta, alinha, normaliza |
⬆ Output do shellcheck a identificar problemas num script: repara nos números de linha e sugestões
.bashrc vs .bash_profile vs .profile
A confusão entre estes ficheiros é lendária. Vamos simplificar:
| Ficheiro | Quando é lido |
|---|---|
| ~/.bash_profile | Login shells (ssh, terminal ao abrir) |
| ~/.bashrc | Shells interativos não-login (terminal dentro de terminal) |
| ~/.profile | Fallback se ~/.bash_profile não existir |
A dica de ouro: source um pelo outro para não teres duplicação:
Exemplo completo: script de backup com boas práticas
O shebang correto
Usa sempre #!/usr/bin/env bash em vez de #!/bin/bash. Porquê?
- env procura o Bash no $PATH do utilizador
- Funciona em macOS (onde /bin/bash é versão antiga) e em NixOS (onde o Bash não está em /bin)
- Mais portável entre sistemas
Dica final: O teu script devia começar sempre com o bloco: #!/usr/bin/env bash, set -euo pipefail, e a declaração de readonly constants. O shellcheck devia passar sem warnings. E cada função devia caber no ecrã sem scroll. Segue estas regras e os teus scripts vão durar anos.
Recapitulando
- set -euo pipefail em todo o lado: error handling não é opcional
- trap para limpeza e logging de erros
- $() para substituição, () para subshells, {} para grouping
- Funções com local, validação de argumentos e return consistente
- Quoting SEMPRE nas variáveis, [[ ]] em vez de [ ]
- ${VAR:-default} para valores por omissão
- shellcheck antes de cada deploy
O Bash é uma linguagem traiçoeira. Mas com disciplina, as ferramentas certas e estas boas práticas, os teus scripts vão ser robustos, legíveis e portáveis.
Experimenta executar o shellcheck num dos teus scripts antigos. Aposto que encontras pelo menos 5 coisas para corrigir.
Comentários (0)
Nenhum comentário ainda. Seja o primeiro!
Deixar comentário