Scripting Avançado em Bash: Dominando Recursos do Shell para Automação
Aprenda scripting avançado em Bash com arrays, substituição de processos, modo estrito, ShellCheck e expansão de parâmetros para automação mais segura.
Scripting Avançado em Bash: Dominando Recursos do Shell para Automação
O scripting em Bash fica mais difícil quando seu script cresce de alguns comandos para automação real. Você precisa de manipulação de variáveis mais segura, entrada e saída mais limpas e menos arquivos temporários.
Este guia aborda recursos avançados de scripting em Bash que você pode usar em scripts de implantação, verificações de log e tarefas de manutenção. O objetivo não é código shell engenhoso. É código que você pode reexecutar, depurar e entregar a outro engenheiro.
1. Use Arrays do Bash para Listas Reais
Arrays permitem armazenar múltiplos valores sem dividir strings por espaços. Isso é importante quando nomes de arquivos, nomes de serviços ou entrada do usuário contêm espaços.
Arrays Indexados
Arrays indexados são o tipo mais comum, onde os elementos são acessados usando um índice numérico começando em 0.
Exemplo:
# Inicializa um array indexado
CORES=("vermelho" "verde" "azul" "amarelo")
# Acessando elementos
echo "A segunda cor é: ${CORES[1]}"
# Adicionando um elemento
CORES+=( "roxo" )
# Imprimindo todos os elementos
echo "Todas as cores: ${CORES[@]}"
Operações comuns com arrays:
| Operação | Sintaxe | Descrição |
|---|---|---|
| Obter Contagem de Elementos | ${#ARRAY[@]} |
Retorna o número total de elementos. |
| Obter Comprimento de Elemento Específico | ${#ARRAY[indice]} |
Retorna o comprimento da string em um índice específico. |
| Iteração | for item in "${ARRAY[@]}" |
Estrutura de loop padrão para processar todos os elementos. |
Sempre coloque entre aspas as expansões de array com "${ARRAY[@]}". Isso mantém "/var/log/meu app.log" como um argumento em vez de dois.
Arrays Associativos
Arrays associativos funcionam como pequenos mapas chave-valor. Eles exigem Bash 4 ou posterior, então verifique seus sistemas de destino se você suporta hosts macOS mais antigos.
Você deve declarar um array associativo com -A:
# Declara como array associativo
declare -A MAPA_CONFIG
# Atribui pares chave-valor
MAPA_CONFIG["porta"]=8080
MAPA_CONFIG["hostname"]="localhost"
MAPA_CONFIG["timeout"]=30
# Acessando valores
echo "Porta definida para: ${MAPA_CONFIG["porta"]}"
# Iterando sobre chaves
for chave in "${!MAPA_CONFIG[@]}"; do
echo "Chave: $chave, Valor: ${MAPA_CONFIG[$chave]}"
done
2. Use Substituição de Processos em Vez de Arquivos Temporários
A substituição de processos, escrita como <(comando) ou >(comando), permite que um comando trate a saída de outro comando como um arquivo. É útil quando uma ferramenta espera caminhos de arquivo, mas seus dados vêm de comandos.
Quando Ajuda
Por exemplo, digamos que você precise comparar duas listas de serviços geradas. diff espera caminhos de arquivo, mas você não precisa escrever essas listas em /tmp.
Sem substituição de processos:
# Ineficiente e bagunçado
saida1=$(comando_a)
echo "$saida1" > /tmp/temp1.txt
saida2=$(comando_b)
echo "$saida2" > /tmp/temp2.txt
diff /tmp/temp1.txt /tmp/temp2.txt
rm /tmp/temp1.txt /tmp/temp2.txt
Comparação Direta Mais Limpa
A substituição de processos fornece descritores de arquivo temporários para diff e mantém seu script mais simples.
Com substituição de processos:
# Comparação limpa em uma linha
diff <(comando_a) <(comando_b)
Esse padrão funciona bem com comm, diff e ferramentas que precisam de múltiplas entradas de arquivo.
Variações de Sintaxe:
<(comando)passa a saída do comando para um leitor.>(comando)envia a saída escrita para outro comando.
3. Adicione Modo Estrito e ShellCheck
Scripting avançado em Bash deve falhar ruidosamente quando algo inesperado acontece. O modo estrito ajuda a capturar variáveis ausentes e pipelines quebrados antes que causem danos silenciosos.
Opções Essenciais do Modo Estrito
A maioria dos scripts de automação deve começar com:
set -euo pipefail
-e: Sai quando um comando falha.-u: Trata variáveis não definidas como erros.-o pipefail: Falha um pipeline se qualquer comando no pipeline falhar.
Exemplo:
# Sem pipefail, isso pode parecer bem-sucedido porque wc sai limpo
cat arquivo.log | grep padrao_sucesso | wc -l
# Com set -o pipefail, a falha do grep faz o pipeline falhar.
Use ShellCheck
ShellCheck captura erros de citação, expansões inseguras, código inacessível e problemas comuns de portabilidade.
Execute-o antes de confirmar um script:
shellcheck seu_script.sh
Quando o ShellCheck pedir para você colocar uma variável entre aspas ou usar "${array[@]}", trate isso como um bug real, a menos que você tenha um motivo claro para ignorá-lo.
4. Capture a Saída com Cuidado
A substituição de comandos com $() é útil, mas pode ocultar falhas ou misturar fluxos de saída se você a usar casualmente.
Capturando STDOUT e STDERR
Quando você quiser registrar tudo de um comando, capture tanto a saída padrão quanto o erro padrão:
# Captura stdout e stderr na VARIÁVEL
VARIÁVEL=$(comando_que_pode_falhar 2>&1)
# Descarta stdout e stderr quando você só precisa do código de saída
comando_que_pode_falhar &> /dev/null
Expansão de Parâmetros para Limpeza Inline
A expansão de parâmetros pode limpar strings sem gerar sed ou awk para casos simples.
${variavel%padrao}remove o sufixo correspondente mais curto.${variavel%%padrao}remove o sufixo correspondente mais longo.${variavel#padrao}remove o prefixo correspondente mais curto.${variavel##padrao}remove o prefixo correspondente mais longo.
Exemplo:
ARQUIVO="relatorio.log.bak"
# Remove o sufixo mais curto correspondente a .bak
NOME_LIMPO=${ARQUIVO%.bak}
echo $NOME_LIMPO # Saída: relatorio.log
# Remove todos os sufixos correspondentes a *.bak (remove apenas .bak aqui)
NOME_LIMPO_LONGO=${ARQUIVO%%.*}
echo $NOME_LIMPO_LONGO # Saída: relatorio
Quando Pedir Ajuda
Peça a um usuário de shell mais experiente para revisar seu script quando ele excluir arquivos, alterar serviços de produção, lidar com segredos ou for executado a partir de CI. Bash é poderoso, mas um pequeno erro de citação pode afetar todos os arquivos que correspondem a um padrão.
Conclusão
Use arrays para listas reais, substituição de processos para saída de comando semelhante a arquivo, set -euo pipefail para falhas mais seguras e ShellCheck para feedback rápido. Esses hábitos tornam o scripting avançado em Bash mais fácil de manter e muito menos surpreendente durante execuções de automação.