Escrevi 47 Shell Scripts em 6 Meses — Estes 5 Me Economizaram 30 Horas Por Semana
Eu tinha um problema: toda segunda-feira eu gastava 40 minutos organizando arquivos de projetos, rodando backups manuais e atualizando repositórios Git. Toda. Segunda. Mesma coisa. Até que num dia de raiva, escrevi meu primeiro shell script com mais de 3 linhas.
Seis meses depois, tenho 47 scripts rodando no meu sistema. A maioria é inútil. Mas cinco deles mudaram minha relação com o terminal. Shell script não é só para sysadmin — é para qualquer pessoa que digita o mesmo comando mais de duas vezes por semana.
Neste artigo, vou mostrar como automatizar tarefas repetitivas com shell script, do zero, com código que você pode copiar e usar hoje. Sem teoria excessiva. Sem “hello world”. Apenas automações que resolvem problemas reais.

Por Que Shell Script e Não Python (ou Qualquer Outra Coisa)
Olha, eu amo Python. Mas quando o problema é “copiar esses 12 arquivos, renomear com data de hoje, compactar e mandar pro S3”, Python é matar mosquito com canhão. Shell script já fala a língua do sistema.
Vantagens que ninguém te conta:
- Zero dependência — funciona em qualquer Linux e macOS sem instalar nada
- Pipeline nativo —
grep | sed | awk | sorté o superpoder que você subestima - Cron + script = automação — agende com
crontab -ee esqueça - Debug instantâneo —
bash -x script.shmostra cada linha executada
A desvantagem? A sintaxe é feia. Variáveis sem espaço, colchetes que parecem obras de arte abstrata, e mensagens de erro que parecem xingamentos em alienígena. Mas você convive. Todo mundo convive.
Antes de Começar: Seu Ambiente de Automação
Se você tá no Linux, já tem tudo. No macOS, também. No Windows? Instale o WSL2 e entre no mundo real.
Crie uma estrutura organizada:
# Sua pasta de scripts
mkdir -p ~/scripts/{backup,git,web,utils}
# Torne executável
cd ~/scripts
chmod +x **/*.sh
# Adicione ao PATH
echo 'export PATH="$HOME/scripts:$PATH"' >> ~/.bashrc
source ~/.bashrc
Agora qualquer script que você criar em ~/scripts/ roda de qualquer lugar. Isso muda o jogo porque você para de procurar onde salvou aquele script.
Script 1: Backup Inteligente Que Não Enche o Disco
Este foi o primeiro script que me salvou de verdade. Eu perdia tempo fazendo backup manual de projetos. Às vezes esquecia. Às vezes sobrescrevia o backup anterior sem querer. Resultado: tensão permanente.
#!/usr/bin/env bash
# backup-projetos.sh — Backup incremental com rotação automática
set -euo pipefail
SOURCE_DIR="$HOME/Projetos"
BACKUP_DIR="$HOME/Backups/projetos"
MAX_BACKUPS=7
DATE=$(date +%Y-%m-%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# Backup incremental com rsync (só copia o que mudou)
rsync -av --delete --exclude='node_modules' --exclude='.git' --exclude='__pycache__' --exclude='.venv' "$SOURCE_DIR/" "$BACKUP_DIR/current/"
# Snapshot compactado do estado atual
tar czf "$BACKUP_DIR/snapshot_$DATE.tar.gz" -C "$BACKUP_DIR" "current/"
# Rotação: mantém apenas os últimos N snapshots
ls -t "$BACKUP_DIR"/snapshot_*.tar.gz | tail -n +$((MAX_BACKUPS + 1)) | xargs -r rm --
echo "✅ Backup concluído: snapshot_$DATE.tar.gz"
echo "📊 Tamanho: $(du -sh "$BACKUP_DIR/snapshot_$DATE.tar.gz" | cut -f1)"
O que torna esse script inteligente:
- Incremental com
rsync— só copia arquivos modificados, não tudo - Rotação automática — mantém 7 snapshots, apaga o resto
- Exclusões inteligentes —
node_modulese.venvnão entram no backup set -euo pipefail— falha no primeiro erro, não continua quebrado
Agende no cron para rodar toda noite:
# Edite com crontab -e
# Roda todo dia às 2h da manhã
0 2 * * * /home/seuusuario/scripts/backup/backup-projetos.sh >> /tmp/backup.log 2>&1
Script 2: Sincronização Git Em Lote (Para Quem Tem 15 Repos)
Se você trabalha com múltiplos repositórios, sabe o drama. Status aqui, pull ali, push acolá. Esqueceu de dar push num repo na sexta? Descobriu na segunda quando o colega sobrescreveu seu código. Pediu desculpas. Não adiantou.

#!/usr/bin/env bash
# git-sync-all.sh — Sincroniza todos os repositórios Git em um diretório
set -euo pipefail
WORKSPACE="$HOME/Projetos"
REPORT_FILE="/tmp/git-sync-report-$(date +%Y%m%d).txt"
echo "🔄 Git Sync — $(date)" > "$REPORT_FILE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━" >> "$REPORT_FILE"
cd "$WORKSPACE"
SYNCED=0
PENDING=0
ERRORS=0
for repo in */; do
if [ ! -d "$repo/.git" ]; then
continue
fi
echo -n "⏳ $repo "
cd "$repo"
# Verifica se tem mudanças não commitadas
if [ -n "$(git status --porcelain)" ]; then
BRANCH=$(git branch --show-current)
echo "⚠️ Mudanças pendentes ($BRANCH)" | tee -a "$REPORT_FILE"
git status --short | tee -a "$REPORT_FILE"
PENDING=$((PENDING + 1))
else
# Pull com rebase para manter histórico limpo
if git pull --rebase 2>&1 | grep -q "Already up to date"; then
echo "✅ Atualizado"
else
echo "📥 Atualizado com novas mudanças" | tee -a "$REPORT_FILE"
SYNCED=$((SYNCED + 1))
fi
fi
cd "$WORKSPACE"
done
echo "" >> "$REPORT_FILE"
echo "📊 Resumo: $SYNCED atualizados, $PENDING pendentes, $ERRORS erros" | tee -a "$REPORT_FILE"
cat "$REPORT_FILE"
Eu rodo esse script toda manhã antes do café. Em 30 segundos, sei exatamente o estado de todos os meus repositórios. Se tem algo pendente, o script me diz qual repo e qual arquivo. Sem surpresas.
Script 3: Monitor de Site Que Realmente Avisa Quando o Servidor Cai
Eu usava serviços caros de monitoramento. Depois descobri que 20 linhas de shell faziam a mesma coisa. A diferença? O meu script avisa no Telegram, que é onde eu realmente vejo as notificações.
#!/usr/bin/env bash
# site-monitor.sh — Monitor de disponibilidade com alerta Telegram
set -euo pipefail
# Configuração
SITES=("https://automente.com.br" "https://seusite.com")
TELEGRAM_TOKEN="SEU_BOT_TOKEN"
TELEGRAM_CHAT="SEU_CHAT_ID"
TIMEOUT=10
RETRY=3
LOG_FILE="/tmp/site-monitor.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
alert_telegram() {
local message="$1"
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" -d chat_id="$TELEGRAM_CHAT" -d text="$message" -d parse_mode="HTML" > /dev/null
}
for site in "${SITES[@]}"; do
FAIL_COUNT=0
for i in $(seq 1 $RETRY); do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" "$site" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
break
fi
FAIL_COUNT=$((FAIL_COUNT + 1))
sleep 5
done
if [ "$FAIL_COUNT" -eq "$RETRY" ]; then
log "🚨 $site FORA DO AR (último HTTP: $HTTP_CODE)"
alert_telegram "🚨 Site Down! $site retornou HTTP $HTTP_CODE após $RETRY tentativas. Hora: $(date '+%d/%m/%Y %H:%M')"
else
log "✅ $site OK (HTTP: $HTTP_CODE)"
fi
done
Pontos importantes desse script:
- Retry com delay — não alerta na primeira falha (pode ser blip de rede)
- Alerta via Telegram — você vê, diferente de email que fica na aba de spam
- Log persistente — histórico para análise posterior
- Timeout explícito — não trava esperando um site que não responde
Rode a cada 5 minutos com cron:
# crontab -e
*/5 * * * * /home/seuusuario/scripts/web/site-monitor.sh
Script 4: Organizador de Downloads Que Não Te Julga
Minha pasta Downloads era um depósito. PDFs misturados com ZIPs, screenshots misturados com instaladores. Toda vez que eu precisava de algo, passava 10 minutos procurando. Até que criei um script que organiza tudo por tipo de arquivo e data.
#!/usr/bin/env bash
# organize-downloads.sh — Organiza pasta Downloads por tipo e data
set -euo pipefail
DOWNLOADS="$HOME/Downloads"
MONTH=$(date +%Y-%m)
# Mapa de extensões para categorias
declare -A CATEGORIES=(
[docs]="pdf doc docx odt txt rtf epub"
[images]="jpg jpeg png gif svg webp bmp ico"
[videos]="mp4 mkv avi mov wmv webm"
="mp3 wav flac ogg aac m4a"
[archives]="zip tar gz bz2 rar 7z xz"
[code]="js py sh json yaml yml html css sql csv"
[installers]="deb rpm AppImage exe dmg msi"
)
organize_by_ext() {
local category="$1"
shift
local extensions=("$@")
for ext in "${extensions[@]}"; do
find "$DOWNLOADS" -maxdepth 1 -type f -iname "*.${ext}" -print0 | while IFS= read -r -d '' file; do
dest="$DOWNLOADS/$category/$MONTH"
mkdir -p "$dest"
filename=$(basename "$file")
if [ -f "$dest/$filename" ]; then
base="${filename%.*}"
ext="${filename##*.}"
mv "$file" "$dest/${base}_$(date +%s).${ext}"
else
mv "$file" "$dest/$filename"
fi
done
done
}
for category in "${!CATEGORIES[@]}"; do
read -ra exts <<< "${CATEGORIES[$category]}"
organize_by_ext "$category" "${exts[@]}"
done
echo "📁 Downloads organizados em $(date)"
for dir in "$DOWNLOADS"/*/; do
count=$(find "$dir" -type f | wc -l)
[ "$count" -gt 0 ] && echo " $(basename "$dir"): $count arquivos"
done
O que esse script faz que os outros organizadores não fazem:
- Organiza por mês — dentro de cada categoria, subpastas mensais
- Preserva arquivos — se já existe um com o mesmo nome, renomeia com timestamp
- Relatório visual — mostra o que foi organizado
Script 5: Ambiente de Desenvolvimento Com Um Comando
Esse foi o que me economizou mais tempo. Toda vez que eu começava um projeto novo, gastava 20 minutos configurando: criar pasta, iniciar Git, criar .gitignore, setup do Node ou Python, editor config... Agora é um comando.
#!/usr/bin/env bash
# dev-setup.sh — Cria ambiente de desenvolvimento completo em segundos
set -euo pipefail
PROJECT_NAME="${1:?Uso: dev-setup.sh nome_do_projeto [tipo]}"
PROJECT_TYPE="${2:-node}"
BASE_DIR="$HOME/Projetos"
PROJECT_DIR="$BASE_DIR/$PROJECT_NAME"
if [ -d "$PROJECT_DIR" ]; then
echo "❌ Projeto '$PROJECT_NAME' já existe em $PROJECT_DIR"
exit 1
fi
mkdir -p "$PROJECT_DIR"
cd "$PROJECT_DIR"
# Git init com .gitignore
git init
cat > .gitignore << 'GITIGNORE'
# OS
.DS_Store
Thumbs.db
# IDEs
.vscode/
.idea/
*.swp
*.swo
# Dependencies
node_modules/
.venv/
__pycache__/
*.pyc
# Build
dist/
build/
*.egg-info/
.env
GITIGNORE
# Setup por tipo
setup_node() {
npm init -y > /dev/null
mkdir -p src
echo 'console.log("Hello, world!");' > src/index.js
}
setup_python() {
python3 -m venv .venv
mkdir -p src tests
touch src/__init__.py tests/__init__.py
cat > requirements.txt << 'REQS'
# Dependências aqui
REQS
}
setup_static() {
mkdir -p src/{css,js,assets}
cat > src/index.html << 'HTML'
Novo Projeto
Hello, world!
HTML
touch src/css/style.css src/js/main.js
}
case "$PROJECT_TYPE" in
node|js) setup_node ;;
python|py) setup_python ;;
static|web) setup_static ;;
*) mkdir -p src ;;
esac
# README e primeiro commit
echo "# $PROJECT_NAME" > README.md
git add .
git commit -m "chore: setup inicial via dev-setup.sh"
echo ""
echo "✅ Projeto '$PROJECT_NAME' criado em $PROJECT_DIR"
echo "🎯 Próximo passo: cd $PROJECT_DIR"
Uso:
# Projeto Node
dev-setup.sh meu-app node
# Projeto Python
dev-setup.sh minha-api python
# Site estático
dev-setup.sh meu-portfolio static
Em 3 segundos, você tem: Git inicializado, .gitignore completo, estrutura de pastas, primeiro commit. Antes levava 20 minutos de trabalho manual repetitivo.
O Padrão Que Todos Esses Scripts Seguem
Depois de escrever dezenas de scripts, percebi que os bons seguem o mesmo padrão:
- Entrada validada — checa se diretórios existem, se parâmetros foram passados
- Execução protegida —
set -euo pipefailno topo de TUDO - Saída informativa — logs claros, emojis visuais, resumos no final
- Idempotência — rodar duas vezes não quebra nada
- Configuração no topo — variáveis que o usuário precisa mudar ficam nas primeiras linhas
Se o seu script tem essas 5 coisas, ele é production-ready. Mesmo que só você use.
Como Debugar Shell Script Sem Perder a Sanidade
Shell script tem uma reputação de difícil debug. Justa, por sinal. Mas existem técnicas que transformam isso:
Modo verbose e trace
# Mostra cada comando antes de executar
bash -x seu_script.sh
# Ou ative dentro do script para uma seção específica
set -x # liga trace
# ... código suspeito ...
set +x # desliga trace
Validação defensiva
#!/usr/bin/env bash
set -euo pipefail
# Valida dependências antes de começar
for cmd in rsync curl jq; do
if ! command -v "$cmd" > /dev/null 2>&1; then
echo "❌ '$cmd' não encontrado. Instale antes de rodar."
exit 1
fi
done
# Valida diretório de origem
SOURCE="${1:?Erro: passe o diretório de origem como argumento}"
if [ ! -d "$SOURCE" ]; then
echo "❌ '$SOURCE' não é um diretório válido"
exit 1
fi
Logs estruturados
log() {
local level="$1"
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*" >> "$LOG_FILE"
}
log "INFO" "Iniciando backup"
log "WARN" "Diretório vazio encontrado: $dir"
log "ERROR" "Falha ao copiar: $file"
🔥 Box do Perrengue: Eu uma vez escrevi um script de backup que usava variável
$DATEsem aspas. Funcionou por 3 meses. Até que um dia eu tinha uma pasta chamada2026-04-12no destino, e orm -rf $BACKUP/$DATE/*expandiu pra algo comorm -rf /home/usuario/Backups/2026-04-12 *— com espaço. O asterisco solto apagou TUDO no diretório pai. Perdi 40GB de dados. Sempre use aspas duplas em variáveis. Sempre. Sem exceção. Coloqueset -euo pipefailno topo de cada script. E teste comechoantes derm.
Automatizando a Automação: Cron Como Seu Assistente Pessoal
A mágica dos shell scripts acontece quando você os agenda. O cron é o agendador de tarefas mais subestimado do mundo.
# Edite com: crontab -e
# Backup todo dia às 2h
0 2 * * * ~/scripts/backup/backup-projetos.sh >> /tmp/backup.log 2>&1
# Git sync toda manhã às 8h30 (seg a sex)
30 8 * * 1-5 ~/scripts/git/git-sync-all.sh >> /tmp/git-sync.log 2>&1
# Monitor de site a cada 5 minutos
*/5 * * * * ~/scripts/web/site-monitor.sh >> /tmp/monitor.log 2>&1
# Organizar downloads todo domingo à meia-noite
0 0 * * 0 ~/scripts/utils/organize-downloads.sh >> /tmp/organize.log 2>&1
Dica que ninguém te conta: sempre redirecione a saída para um log. Sem isso, quando algo quebra, você fica voando cego.
Próximos Passos: De Script Para Ferramenta
Seus scripts vão evoluir. O que começa como 10 linhas vira 100, que vira algo que você compartilha. Quando chegar nesse ponto:
- Adicione argumentos —
getoptspra aceitar flags como-vpara verbose - Crie um README — você vai esquecer como usa daqui 3 meses
- Teste com
shellcheck— é um linter para shell script, encontra bugs que você nem sabia que existiam - Versione com Git — seus scripts merecem controle de versão tanto quanto seu código
Instalar o shellcheck é simples:
# Ubuntu/Debian
sudo apt install shellcheck
# macOS
brew install shellcheck
# Uso
shellcheck seu_script.sh
A Matemática da Automação
Vamos contar:
- Backup manual: 15 min/dia × 5 dias = 75 min/semana
- Git sync manual: 10 min/dia × 5 dias = 50 min/semana
- Organizar downloads: 20 min/semana = 20 min/semana
- Setup de projetos: 20 min × 2 projetos = 40 min/semana
Total: ~185 minutos por semana em tarefas que um script faz em 0 segundos da sua parte. Isso é 3 horas por semana ou 156 horas por ano. Quase uma semana inteira de trabalho que você recuperou.
O custo? Duas horas para escrever e testar os scripts. ROI de 78x no primeiro ano.
Comente Aqui: Qual Automação Você Precisa?
Eu quero saber: qual tarefa repetitiva você faz no terminal que poderia ser automatizada? Pode ser qualquer coisa — organização de arquivos, deploy, monitoramento, transformação de dados. Me conta nos comentários que eu ajudo a montar o script.
Se você já automatiza algo com shell script, compartilha aí também. A gente monta uma biblioteca de automações da comunidade. Quem sabe a gente não para de reinventar a roda toda segunda-feira?
Se curtiu esse conteúdo, compartilha com aquele colega que ainda faz backup manual copiando pasta por pasta. A gente salva vidas aqui. E assina a newsletter do AutoMente pra não perder os próximos artigos sobre automação e produtividade.
