Braço robótico industrial amarelo representando automação de processos repetitivos com Bash scripts para produtividade

7 Padrões de Automação Bash Que Transformam 30 Minutos Em 8 Horas de Trabalho Automático

O Dia Em Que O Bash Me Demitiu Do Meu Próprio Trabalho Repetitivo

Eu tinha um ritual sagrado toda segunda-feira: abrir o terminal, rodar 7 comandos diferentes, copiar outputs, colar em planilha, enviar email com resumo, atualizar dashboard e rezar pra nenhum passo quebrar. Levava 45 minutos. Toda. Semana. Sem. Falha.

Aí um dia eu esqueci de rodar. Ninguém notou. O dashboard ficou desatualizado por 3 dias e literalmente nenhuma pessoa reclamou. Foi aí que caiu a ficha: eu estava automatizando o trabalho de um robô que podia ser um robô de verdade.

Se você já sentiu que metade do seu dia é sequência de comandos que um script Bash poderia executar, esse artigo é pra você. Vou te mostrar como construí pipelines de automação com Bash que eliminaram horas de trabalho manual — usando só ferramentas que já vêm no seu Linux.

E não, não vou te dar “10 comandos que todo dev deveria conhecer”. Vou te dar a mentalidade e os padrões que transformam Bash de “linguagem de comando” em “motor de produtividade”.

Teclado iluminado em vermelho com código em tela escura representando automação com scripts Bash no terminal

Padrão 1: Watchdogs — O Robô Que Vigia O Robô

Automatização sem monitoramento é fé cega. Você escreve um script bonito, coloca no cron, e esquece que existe. Até o dia que o servidor reinicia, o serviço morre, e ninguém sabe.

Watchdogs são scripts que verificam se outros scripts/processos estão rodando. Se não estão, eles tomam ação — reiniciam, notificam, ou logam o problema.

O Watchdog Mínimo Viável

#!/bin/bash
# watchdog.sh — Verifica se um processo está rodando e toma ação

PROCESS_NAME="meu-sync-cron"
LOG_FILE="/var/log/watchdog.log"
ALERT_WEBHOOK="https://hooks.slack.com/services/XXX/YYY/ZZZ"

if ! pgrep -f "$PROCESS_NAME" > /dev/null; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $PROCESS_NAME morreu! Reiniciando..." >> "$LOG_FILE"
    
    # Tenta reiniciar
    systemctl restart "$PROCESS_NAME" 2>/dev/null || \
    /opt/scripts/"$PROCESS_NAME".sh &
    
    # Notifica via webhook
    curl -s -X POST "$ALERT_WEBHOOK" \
        -H "Content-Type: application/json" \
        -d "{\"text\":\"🚨 $PROCESS_NAME caiu e foi reiniciado automaticamente em $(hostname)\"}" \
        > /dev/null 2>&1
fi

# Verifica também se o processo está zombie
ZOMBIES=$(ps aux | grep -c 'Z')
if [ "$ZOMBIES" -gt 5 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ALERTA: $ZOMBIES processos zombie detectados!" >> "$LOG_FILE"
fi

Coloque isso no cron a cada 5 minutos e você tem um segurança digital trabalhando 24/7 de graça. Sem Datadog, sem New Relic, sem assinatura mensal.

🔥 Box do Perrengue: Uma vez, meu watchdog mesmo morreu. Resultado: o serviço principal caiu, o watchdog não reiniciou, e eu fiquei 2 dias sem perceber. A solução? Coloquei o watchdog dentro do cron do root, não do user. Se o user desloga, o cron morre. O root cron é imortal. Lição que custou um final de semana de retrabalho.

Padrão 2: Traps — Tratamento de Erros Que Não Deixa Corpo No Chão

Scripts Bash são como aquele colega que nunca avisa quando erra. Rodou? Maravilha. Falhou? Silêncio total. O processo some, o log não existe, e você fica caçando fantasma.

trap é o mecanismo que transforma scripts silenciosos em scripts responsáveis. Ele captura sinais (CTRL+C, erros, saída) e executa funções de limpeza.

Template de Script Profissional com Traps

#!/bin/bash
set -euo pipefail  # Morre no primeiro erro, variável undefined quebra, pipe falha

# --- Configuração ---
SCRIPT_NAME=$(basename "$0")
LOCK_FILE="/tmp/${SCRIPT_NAME}.lock"
LOG_DIR="/var/log/automacao"
LOG_FILE="${LOG_DIR}/${SCRIPT_NAME%.*}-$(date +%Y%m%d).log"
RETENTION_DAYS=30

mkdir -p "$LOG_DIR"

# --- Logging ---
log() {
    local level="$1"; shift
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" | tee -a "$LOG_FILE"
}

# --- Cleanup Function (chamada pelo trap) ---
cleanup() {
    local exit_code=$?
    
    if [ $exit_code -ne 0 ]; then
        log "ERROR" "Script falhou com código $exit_code"
        # Envia alerta
        notify-send "Automação Falhou" "$SCRIPT_NAME morreu. Verifique $LOG_FILE" 2>/dev/null || true
    else
        log "INFO" "Script completou com sucesso"
    fi
    
    # Remove arquivos temporários
    rm -f "${LOCK_FILE}" "/tmp/${SCRIPT_NAME}_*" 2>/dev/null || true
    
    # Rotaciona logs antigos
    find "$LOG_DIR" -name "*.log" -mtime +${RETENTION_DAYS} -delete 2>/dev/null || true
    
    exit $exit_code
}

# --- Registra os traps ---
trap cleanup EXIT INT TERM

# --- Proteção contra execução dupla ---
if [ -f "$LOCK_FILE" ]; then
    PID=$(cat "$LOCK_FILE")
    if kill -0 "$PID" 2>/dev/null; then
        log "WARN" "Já existe uma instância rodando (PID $PID). Saindo."
        exit 1
    fi
    log "WARN" "Lock file órfão encontrado. Removendo."
    rm -f "$LOCK_FILE"
fi
echo $$ > "$LOCK_FILE"

# --- O Script de Verdade Começa Aqui ---
log "INFO" "Iniciando execução"

# Seu código vai aqui
log "INFO" "Processamento concluído"

Isso te dá: log estruturado, proteção contra execução dupla, limpeza automática, rotação de logs e notificação de erro. Tudo num template reutilizável.

Se você quer ir mais fundo em organização de configs e scripts, automatizei meus dotfiles com GNU Stow e Ansible — mesma mentalidade, aplicada ao seu ambiente inteiro.

Padrão 3: Pipeflows — Encadeando Comandos Como Ninguém Te Ensinou

Todo mundo sabe que | passa a saída de um comando pro outro. Mas poucos usam o verdadeiro poder dos pipes — que é transformar problemas complexos em pipelines de 3-4 comandos.

Código colorido em tela de computador mostrando script de automação Bash para produtividade

Exemplo Real: Relatório de Logs de Servidor Em Um Comando

# Top 10 IPs que mais bateram no servidor hoje, com contagem e geolocalização
cat /var/log/nginx/access.log | \
    grep "$(date '+%d/%b/%Y')" | \
    awk '{print $1}' | \
    sort | \
    uniq -c | \
    sort -rn | \
    head -10 | \
    while read count ip; do
        geo=$(curl -s "http://ip-api.com/json/$ip" | jq -r '.country')
        printf "%5d hits | %-15s | %s\n" "$count" "$ip" "$geo"
    done

Em 7 comandos encadeados você tem um mini-sistema de inteligência de segurança. Quer ter ido mais longe em segurança? montei um honeypot SSH com Docker e aprendi muito com as tentativas de invasão.

Template de Pipeflow Reutilizável

#!/bin/bash
# pipeflow-template.sh — Pipeline genérico de processamento

INPUT="${1:-/dev/stdin}"
OUTPUT="${2:-/dev/stdout}"
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT

# Estágio 1: Coleta
collect() {
    cat "$INPUT"
}

# Estágio 2: Filtragem
filter() {
    grep -v '^#' | grep -v '^$'  # Remove comentários e linhas vazias
}

# Estágio 3: Transformação
transform() {
    awk -F',' '{
        # Sua lógica de transformação aqui
        print $1 "|" $2 "|" $3
    }'
}

# Estágio 4: Saída formatada
format() {
    column -t -s '|'
}

# Executa o pipeline
collect | filter | transform | format > "$OUTPUT"

echo "Pipeline completo. Resultado em $OUTPUT" >&2

A beleza disso? Cada estágio é testável independentemente. O filtro quebrou? Rode só collect | filter e veja a saída. A transformação tá errada? filter | transform isolado. É debug modular num language que ninguém espera.

Padrão 4: Automação Baseada em Eventos com inotifywait

Automação de verdade não é “roda todo dia às 9h”. É roda quando algo acontece. O pacote inotify-tools transforma o Bash num sistema reativo.

#!/bin/bash
# auto-process.sh — Processa arquivos assim que chegam num diretório

WATCH_DIR="/opt/incoming"
PROCESSED_DIR="/opt/processed"
ERROR_DIR="/opt/errors"

mkdir -p "$WATCH_DIR" "$PROCESSED_DIR" "$ERROR_DIR"

log() {
    echo "[$(date '+%H:%M:%S')] $*"
}

inotifywait -m -e create -e moved_to "$WATCH_DIR" --format '%f' | \
while read filename; do
    FILEPATH="${WATCH_DIR}/${filename}"
    log "Novo arquivo detectado: $filename"
    
    # Aguarda o arquivo estar completo (não sendo mais escrito)
    sleep 2
    
    # Processa baseado na extensão
    case "$filename" in
        *.csv)
            log "Processando CSV: $filename"
            if python3 /opt/scripts/process_csv.py "$FILEPATH"; then
                mv "$FILEPATH" "$PROCESSED_DIR/"
                log "✅ CSV processado com sucesso"
            else
                mv "$FILEPATH" "$ERROR_DIR/"
                log "❌ Falha ao processar CSV"
            fi
            ;;
        *.json)
            log "Validando JSON: $filename"
            if jq empty "$FILEPATH" 2>/dev/null; then
                mv "$FILEPATH" "$PROCESSED_DIR/"
                log "✅ JSON válido, movido para processamento"
            else
                mv "$FILEPATH" "$ERROR_DIR/"
                log "❌ JSON inválido"
            fi
            ;;
        *)
            log "⚠️ Tipo desconhecido: $filename"
            mv "$FILEPATH" "$ERROR_DIR/"
            ;;
    esac
done

Isso substitui qualquer sistema de file-watching caro. Upload de arquivos, drops de CSV de clientes, logs que chegam — tudo processado automaticamente, em tempo real.

Padrão 5: Paralelização Com xargs e GNU Parallel

Se você tem 100 coisas pra processar e roda uma por vez, está gastando tempo que não precisa. Bash paraleliza naturalmente — você só precisa saber pedir.

Processamento Paralelo Com xargs

# Redimensiona 500 imagens usando todos os cores disponíveis
find ./images -name '*.jpg' -print0 | \
    xargs -0 -P $(nproc) -I {} convert {} -resize 1920x1080 {}_resized.jpg

# Verifica 200 URLs em paralelo (10 por vez)
cat urls.txt | \
    xargs -P 10 -I {} sh -c 'curl -s -o /dev/null -w "%{http_code} {}\n" {}' \
    > status_codes.txt

GNU Parallel Para Controle Fino

#!/bin/bash
# parallel-backup.sh — Backup de múltiplos bancos em paralelo

DATABASES=$(mysql -e "SHOW DATABASES" -s --skip-column-names | grep -v information_schema)

echo "$DATABASES" | parallel -j 4 --bar --eta '
    DB={}
    mysqldump --single-transaction "$DB" | gzip > "/backup/${DB}-$(date +%Y%m%d).sql.gz" && \
    echo "✅ $DB backed up" || echo "❌ $DB failed"
'

echo "Backup completo de $(echo "$DATABASES" | wc -l) bancos"

Aqui a gente conecta com a mentalidade de shell scripts que me economizaram 30 horas por semana — mesmos princípios, agora com paralelismo.

Padrão 6: Notificações Inteligentes — Sem Spam, Com Contexto

Automação que não comunica é automação invisível. Mas automação que spamma é automação ignorada. O segredo é notificar com contexto e apenas quando necessário.

#!/bin/bash
# notify.sh — Sistema de notificações inteligentes

LAST_NOTIFY_FILE="/tmp/.last_notify_$(basename $0)"
THROTTLE_MINUTES=30  # Máximo uma notificação a cada 30 min

notify_smart() {
    local level="$1"
    local message="$2"
    local title="${3:-Automação}"
    
    # Throttle: não notifica se notificou há menos de X minutos
    if [ -f "$LAST_NOTIFY_FILE" ]; then
        LAST=$(stat -c %Y "$LAST_NOTIFY_FILE")
        NOW=$(date +%s)
        DIFF=$(( (NOW - LAST) / 60 ))
        if [ "$DIFF" -lt "$THROTTLE_MINUTES" ] && [ "$level" != "CRITICAL" ]; then
            return 0  # Silenciosamente ignora
        fi
    fi
    
    # Formata mensagem com emoji baseado no nível
    case "$level" in
        SUCCESS) emoji="✅" ;;
        WARNING) emoji="⚠️" ;;
        ERROR)   emoji="🔴" ;;
        CRITICAL) emoji="🚨" ;;
        INFO)    emoji="ℹ️" ;;
        *)       emoji="📌" ;;
    esac
    
    # Envia pra múltiplos canais
    local full_msg="$emoji [$level] $message"
    
    # Telegram (se configurado)
    if [ -n "$TELEGRAM_BOT_TOKEN" ]; then
        curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
            -d chat_id="$TELEGRAM_CHAT_ID" \
            -d text="$full_msg" \
            -d parse_mode="HTML" > /dev/null 2>&1
    fi
    
    # Desktop notification (se local)
    notify-send "$title" "$message" 2>/dev/null || true
    
    # Log sempre
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $full_msg" >> "${LOG_FILE:-/dev/null}"
    
    touch "$LAST_NOTIFY_FILE"
}

# Uso:
# notify_smart SUCCESS "Backup de 12 bancos completado em 3m42s"
# notify_smart CRITICAL "Disco em 98% — intervenção imediata necessária"

Esse padrão é o que uso em produção. Notificações contextuais, com throttling, e via múltiplos canais. Se você quer ver como isso escala, o sistema de aprovação automático com n8n que construí usa a mesma filosofia.

Padrão 7: Orquestração de Pipelines Com Makefile

Makefile não é só pra compilar C. É o orquestrador de pipelines mais subestimado que existe. Define dependências, paraleliza automaticamente e documenta seu workflow.

# Makefile — Orquestração do pipeline de dados diário

.PHONY: all clean extract transform load notify

# Variáveis
DATE := $(shell date +%Y%m%d)
DATA_DIR := ./data/$(DATE)
LOG_DIR := ./logs

# Pipeline completo (dependências em ordem)
all: extract transform load notify

# Estágio 1: Extração (roda em paralelo)
extract: extract-api extract-database extract-csv
	@echo "✅ Extração completa"

extract-api:
	@mkdir -p $(DATA_DIR)
	@echo "Extraindo dados da API..."
	@curl -s "https://api.example.com/data" | jq '.' > $(DATA_DIR)/api.json

extract-database:
	@mkdir -p $(DATA_DIR)
	@echo "Extraindo dados do banco..."
	@psql -c "COPY (SELECT * FROM metrics WHERE date = CURRENT_DATE) TO STDOUT WITH CSV HEADER" > $(DATA_DIR)/db.csv

extract-csv:
	@mkdir -p $(DATA_DIR)
	@echo "Copiando CSVs do SFTP..."
	@scp server:/data/daily/*.csv $(DATA_DIR)/

# Estágio 2: Transformação (depende de extract)
transform:
	@echo "Transformando dados..."
	@python3 scripts/transform.py $(DATA_DIR)

# Estágio 3: Carregamento (depende de transform)
load:
	@echo "Carregando no warehouse..."
	@python3 scripts/load.py $(DATA_DIR)

# Notificação final
notify:
	@echo "📧 Enviando resumo..."
	@./scripts/notify.sh "Pipeline diário completo: $(DATE)"

# Limpeza
clean:
	@rm -rf $(DATA_DIR)
	@echo "🧹 Dados limpos"

# Help (porque documentação importa)
help:
	@echo "Pipeline de dados diário"
	@echo ""
	@echo "Comandos:"
	@echo "  make all       - Executa pipeline completo"
	@echo "  make extract   - Só extração"
	@echo "  make transform - Só transformação"
	@echo "  make clean     - Remove dados do dia"

Com make -j4 all, os três extracts rodam em paralelo. O Make resolve as dependências sozinho. E make help documenta tudo. Simples, poderoso, zero dependência.

Como Juntar Tudo Num Sistema Coeso

Agora que você tem os 7 padrões, aqui vai como eles se conectam:

  1. Cron dispara o Makefile no horário certo
  2. O Makefile orquestra os estágios com paralelização
  3. Cada script tem trap pra limpeza e logging
  4. O watchdog verifica se tudo está rodando
  5. Notificações inteligentes te mantêm informado sem spam
  6. Pipeflows processam dados entre estágios
  7. inotifywait adiciona reatividade pra eventos em tempo real

A estrutura de diretórios fica assim:

/opt/automacao/
├── Makefile                    # Orquestrador principal
├── scripts/
│   ├── extract-api.sh          # Cada script usa o template com trap
│   ├── extract-db.sh
│   ├── transform.py
│   ├── load.py
│   ├── notify.sh               # Sistema de notificações
│   └── watchdog.sh             # Monitoramento
├── configs/
│   ├── .env                    # Variáveis sensíveis
│   └── templates/              # Templates reutilizáveis
├── logs/
│   └── YYYY-MM-DD/             # Logs organizados por data
└── data/
    ├── incoming/               # inotifywait monitora aqui
    ├── processing/
    ├── processed/
    └── errors/

Cada peça é independente, testável e substituível. Precisa trocar o Python por Rust? Só o script de transformação muda. O Makefile, o watchdog e as notificações continuam iguais.

O Que Eu Aprendi Automatizando Tudo Isso (E O Que Daria Errado)

Depois de meses rodando esse tipo de automação, aqui vão as verdades desconfortáveis:

  • Automação ruim é pior que manual. Automatizar um processo mal definido amplifica o problema. Mapeie o fluxo manual antes de scriptar.
  • Logging salva vidas. Quando (não se) algo quebra, logs detalhados são a diferença entre 5 minutos e 5 horas de debug.
  • Idempotência não é opcional. Seu script precisa poder rodar 10 vezes sem duplicar dados ou quebrar estado. mkdir -p, touch, e checks condicionais são seus amigos.
  • Cron é confiável, mas não invisível. Use automações do dia a dia como base, mas sempre valide que estão rodando.
  • Documentação é parte do script. Se você precisa explicar verbalmente como rodar, a automação está incompleta.

🔥 Box do Perrengue #2: Uma vez automatizei o envio de relatórios diários. Funcionou lindamente por 3 semanas. Aí mudou o timezone do servidor (DST automático), o cron passou a rodar 1h mais cedo, e o relatório ia com dados incompletos. O cliente achou que estávamos escondendo números. A solução? TZ=America/Sao_Paulo na crontab. Sempre fixe o timezone nos cronjobs. Sempre.

Template Final: Script Boilerplate Production-Ready

Junta tudo num único template que você copia pra cada novo script:

#!/bin/bash
# ============================================================================
# Script: [NOME]
# Descrição: [O QUE FAZ]
# Uso: ./script.sh [argumentos]
# Cron: [expressão cron se aplicável]
# Autor: [seu nome]
# Última atualização: 2026-04-19
# ============================================================================

set -euo pipefail

# --- Configuração ---
readonly SCRIPT_NAME=$(basename "$0")
readonly SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
readonly LOCK_FILE="/tmp/${SCRIPT_NAME}.lock"
readonly LOG_FILE="${SCRIPT_DIR}/logs/${SCRIPT_NAME%.*}-$(date +%Y%m%d).log"
readonly TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

# --- Funções ---
log() { local lvl="$1"; shift; echo "[$TIMESTAMP] [$lvl] $*" | tee -a "$LOG_FILE"; }

cleanup() {
    local rc=$?
    [ $rc -eq 0 ] && log "INFO" "Sucesso" || log "ERROR" "Falha (código $rc)"
    rm -f "$LOCK_FILE"
    exit $rc
}

trap cleanup EXIT INT TERM

# Lock
[ -f "$LOCK_FILE" ] && { log "WARN" "Já rodando (PID $(cat "$LOCK_FILE"))"; exit 1; }
echo $$ > "$LOCK_FILE"

# --- Main ---
log "INFO" "Iniciando $SCRIPT_NAME"

# SEU CÓDIGO AQUI

log "INFO" "Concluído"

Copie, adapte, repita. Em 2 semanas você tem uma biblioteca de scripts que rodam sozinhos, se monitoram, e te avisam quando algo foge do controle.

E Você? Qual Automação Vai Construir Primeiro?

Pense numa tarefa que você repete toda semana. Agora imagine ela rodando sozinha enquanto você toma café. Isso não é futuro — é Bash bem escrito com os padrões certos.

Me conta nos comentários: qual é a tarefa repetitiva que você mais quer automatizar? Quem sabe a gente não constrói o script juntos no próximo post?

E se você quer ver como automação escala pra sistemas inteiros, dê uma olhada em como construí um pipeline RAG do zero e como agentes autônomos com tool use funcionam. A mentalidade é a mesma: automatizar o repetível pra focar no que importa.

Posts Similares