Cheatsheet Cron Jobs
Agendamento de tarefas em sistemas Unix/Linux
Cron Jobs
Sintaxe e Campos
Estrutura base
# ┌──────── minuto (0-59) # │ ┌────── hora (0-23) # │ │ ┌──── dia do mês (1-31) # │ │ │ ┌── mês (1-12) # │ │ │ │ ┌─ dia da semana (0-7) # │ │ │ │ │ # * * * * * comando-a-executar # 0 e 7 = domingo
Cada * representa um campo temporal. Os 5 campos definem QUANDO executar. O restante é o comando. A ordem é fixa: minuto, hora, dia, mês, semana. 0 e 7 ambos significam domingo.
Campo dia da semana
# Dia da semana (0-7, 0 e 7 = domingo) 0 9 * * 1 # segunda às 09:00 0 9 * * 1-5 # seg a sex às 09:00 0 0 * * 0 # domingo à meia-noite 0 9 * * MON # = 1 (nomes: SUN-SAT) 0 9 * * 6,0 # sábado e domingo # NOTA: se dia-mês E dia-semana forem # restritos, executa em QUALQUER um (OR)
O quinto campo é o dia da semana (0-7). Aceita nomes: SUN, MON, TUE... Se ambos dia-mês e dia-semana estiverem restritos (não *), o cron executa quando QUALQUER corresponder (lógica OR, não AND).
Campo minuto
# Minuto (0-59) 0 * * * * # no início de cada hora 30 * * * * # a cada meia hora */5 * * * * # a cada 5 minutos 15,45 * * * * # aos 15 e 45 minutos 0-30 * * * * # minutos 0 a 30 (cada min)
O primeiro campo controla o minuto (0-59). 0 executa no início da hora. */5 executa de 5 em 5 minutos. É o campo mais usado para tarefas frequentes. Valores válidos: 0 a 59.
Campo hora
# Hora (0-23, formato 24h) 0 3 * * * # às 03:00 0 15 * * * # às 15:00 0 9,12,18 * * * # às 09h, 12h e 18h 0 9-17 * * * # de hora a hora, 09h às 17h 0 */6 * * * # a cada 6 horas (0h,6h,12h,18h)
O segundo campo define a hora (0-23). Formato 24h sem AM/PM. 9-17 cobre horário laboral. */6 executa a cada 6 horas. Combine com minuto 0 para horas exactas.
Campos dia e mês
# Dia do mês (1-31) 0 0 1 * * # dia 1 de cada mês 0 0 15 * * # dia 15 de cada mês 0 0 1,15 * * # dias 1 e 15 # Mês (1-12 ou JAN-DEC) 0 0 1 1 * # 1 de Janeiro 0 0 1 6,12 * # Junho e Dezembro 0 0 * 1-3 * # Jan, Fev e Mar (diário)
O terceiro campo é o dia do mês (1-31). O quarto é o mês (1-12 ou nomes JAN-DEC). Se dia for *, executa todos os dias. Cuidado: dia 31 não existe em todos os meses.
Operadores e Valores
Asterisco (todos)
* * * * * # cada minuto (todos os valores) 0 * * * * # minuto 0 de CADA hora 0 0 * * * # meia-noite de CADA dia 0 0 1 * * # dia 1 de CADA mês # * = "qualquer valor" para esse campo # Equivale ao intervalo completo: # * no minuto = 0-59 # * na hora = 0-23
O * significa "todos os valores possíveis" para o campo. No minuto equivale a 0-59, na hora a 0-23. É o valor por defeito. Use quando não quer restringir esse campo específico.
Atalhos especiais
@reboot # ao iniciar o sistema @yearly # = 0 0 1 1 * (1 Jan, 00:00) @annually # = @yearly @monthly # = 0 0 1 * * (dia 1, 00:00) @weekly # = 0 0 * * 0 (domingo, 00:00) @daily # = 0 0 * * * (meia-noite) @midnight # = @daily @hourly # = 0 * * * * (início da hora) # Mais legíveis que a sintaxe numérica
Os atalhos @daily, @hourly etc. substituem expressões numéricas. @reboot executa uma vez ao arrancar o sistema. São mais legíveis e menos propensos a erros. Nem todos os sistemas suportam todos os atalhos — verifique a documentação.
Vírgula (lista)
# Lista de valores separados por vírgula 0 9,12,15 * * * # às 09h, 12h e 15h 0 0 1,15 * * # dias 1 e 15 0 9 * * 1,3,5 # seg, qua e sex 0 0 * 1,4,7,10 * # Jan, Abr, Jul, Out # Pode combinar com intervalos: 0 9-12,14-17 * * * # 9h-12h e 14h-17h
A vírgula cria uma lista de valores discretos. 9,12,15 executa nessas 3 horas. Pode misturar com intervalos: 9-12,14-17. Sem espaços após a vírgula. Ideal para horários específicos múltiplos.
Hífen (intervalo)
# Intervalo contínuo de valores 0 9-17 * * * # de hora a hora, 09h às 17h 0 0 * * 1-5 # segunda a sexta */10 8-18 * * * # a cada 10min, 08h às 18h 0 0 1-15 * * # primeiros 15 dias do mês # O intervalo é inclusivo: # 9-17 = 9,10,11,12,13,14,15,16,17
O hífen define um intervalo contínuo e inclusivo. 9-17 inclui 9, 10, 11... até 17. 1-5 no dia da semana = seg a sex. Combine com / para passos dentro do intervalo: 8-18/2 = horas pares.
Barra (passo)
# Passo: executa a cada N unidades */5 * * * * # a cada 5 minutos */15 * * * * # a cada 15 minutos 0 */2 * * * # a cada 2 horas 0 */6 * * * # a cada 6 horas 0 9-17/2 * * * # 9h, 11h, 13h, 15h, 17h # */N = "a cada N" a partir do mínimo # Equivale a: 0-N/max com passo N
A barra define o passo (frequência). */5 = a cada 5 unidades. */15 no minuto = 0, 15, 30, 45. Pode combinar com intervalo: 9-17/2 = horas ímpares entre 9 e 17. Muito usado para tarefas periódicas.
Exemplos Práticos
Backups diários
# Backup da BD às 02:30 todos os dias 30 2 * * * /usr/bin/mysqldump -u root minha_bd > /backups/bd_$(date +\%F).sql # Backup de ficheiros às 03:00 0 3 * * * tar -czf /backups/site_$(date +\%F).tar.gz /var/www # Limpar backups com mais de 30 dias 0 4 * * * find /backups -mtime +30 -delete
Backups são o uso mais comum do cron. $(date +\%F) gera nome com data (escape o % com \). Combine backup + limpeza automática. Agende em horário de baixo tráfego (madrugada).
Scripts com PHP e Node
# PHP com caminho absoluto 0 3 * * * /usr/bin/php /var/www/app/cron.php # Laravel Artisan * * * * * cd /app && php artisan schedule:run # Node.js */10 * * * * /usr/bin/node /scripts/worker.js # Python 0 */4 * * * /usr/bin/python3 /scripts/etl.py # Sempre use caminhos ABSOLUTOS
Sempre use o caminho absoluto do interpretador (/usr/bin/php). O cron não carrega o PATH do utilizador. Para Laravel, o padrão é schedule:run a cada minuto. Use cd se o script depende do directório de trabalho.
Tarefas frequentes
# A cada 5 minutos: verificar fila */5 * * * * php /app/artisan queue:work --stop-when-empty # A cada hora: limpar cache 0 * * * * php /app/artisan cache:clear # A cada 15 minutos: sync de dados */15 * * * * /app/scripts/sync.sh # A cada minuto: monitorização * * * * * curl -s https://meu-site.com/health
Tarefas recorrentes usam */N para frequência. */5 = 5 minutos, */15 = 15 minutos. Para Laravel, prefira o schedule interno. curl para health checks simples. Evite tarefas a cada minuto se possível.
Horário laboral
# Relatórios às 09:00 de seg a sex 0 9 * * 1-5 /scripts/relatorio_diario.sh # Lembrete às 17:30 de seg a sex 30 17 * * 1-5 /scripts/lembrete.sh # Limpeza de sessão a cada 30min (24/7) */30 * * * * php /app/artisan session:gc # Verificação a cada 2h em dias úteis 0 9-18/2 * * 1-5 /scripts/check.sh
1-5 no dia da semana restringe a seg-sex. Combine com 9-17 na hora para horário laboral. 9-18/2 executa às 9h, 11h, 13h, 15h, 17h. Tarefas de manutenção podem correr 24/7 com * no dia.
Mensais e anuais
# Facturação no dia 1 às 06:00 0 6 1 * * /scripts/facturacao.sh # Relatório trimestral (Jan,Abr,Jul,Out) 0 8 1 1,4,7,10 * /scripts/trimestral.sh # Renovação de certificados (dia 15) 0 3 15 * * certbot renew --quiet # Aniversário do sistema (1 Jan) 0 0 1 1 * /scripts/aniversario.sh
Tarefas mensais fixam o dia do mês: 0 6 1 * * = dia 1 às 6h. Trimestral usa lista de meses: 1,4,7,10. certbot renew é um caso clássico mensal. Para "último dia do mês", use lógica no script.
Gestão e CLI
Comandos crontab
crontab -e # editar crontab do utilizador crontab -l # listar entradas actuais crontab -r # remover TODAS as entradas crontab -u user -e # editar de outro user # Editar com editor específico: EDITOR=nano crontab -e EDITOR=vim crontab -e
crontab -e abre o editor para gerir jobs. -l lista sem editar. -r apaga tudo (cuidado!). -u para outro utilizador (requer root). O editor é definido por EDITOR ou VISUAL.
Ficheiros do sistema
/etc/crontab # crontab do sistema /etc/cron.d/ # jobs de pacotes /var/spool/cron/ # crontabs de utilizadores # Directórios de execução automática: /etc/cron.hourly/ # scripts a cada hora /etc/cron.daily/ # scripts diários /etc/cron.weekly/ # scripts semanais /etc/cron.monthly/ # scripts mensais # Basta colocar um script executável lá
/etc/crontab é o ficheiro global do sistema. /etc/cron.d/ para jobs de pacotes. Os directórios cron.daily/ etc. executam scripts automaticamente — basta copiar um ficheiro executável. Mais simples que editar crontab para tarefas standard.
Permissões e controlo
# Permitir utilizadores: /etc/cron.allow # whitelist (só estes) /etc/cron.deny # blacklist (todos excepto) # Verificar serviço: systemctl status cron systemctl restart cron systemctl enable cron # arranque automático # Logs (Ubuntu/Debian): grep CRON /var/log/syslog
cron.allow e cron.deny controlam quem pode usar cron. Se cron.allow existir, só listados podem. O serviço chama-se cron (Debian) ou crond (RHEL). Logs em /var/log/syslog filtrando CRON.
Redireccionar output
# Guardar output em ficheiro: 0 3 * * * /script.sh >> /var/log/job.log 2>&1 # Descartar output (silenciar): 0 3 * * * /script.sh > /dev/null 2>&1 # Só guardar erros: 0 3 * * * /script.sh 2>> /var/log/erros.log # Enviar por email (se MAILTO definido): MAILTO=admin@exemplo.com 0 3 * * * /script.sh
Por defeito, o cron envia output por email. >> /ficheiro 2>&1 guarda stdout e stderr. > /dev/null 2>&1 silencia tudo. 2>> só captura erros. MAILTO define destinatário dos emails. Sempre redireccione para evitar emails indesejados.
Avançado e Boas Práticas
Variáveis de ambiente
# Definir no topo do crontab: SHELL=/bin/bash PATH=/usr/local/bin:/usr/bin:/bin MAILTO=admin@exemplo.com HOME=/home/deploy # Ou inline no comando: 0 3 * * * DB_PASS=secret /script.sh # Carregar env de ficheiro: 0 3 * * * . /home/user/.env && /script.sh
O cron tem um PATH mínimo — defina explicitamente. SHELL define o interpretador. MAILTO controla emails. Use . /ficheiro.env para carregar variáveis. Sem isto, comandos como node ou composer não são encontrados.
Evitar sobreposição
# flock: impede execução simultânea */5 * * * * flock -n /tmp/job.lock /script.sh # Alternativa com PID file: * * * * * [ ! -f /tmp/job.pid ] && /script.sh & echo $! > /tmp/job.pid # systemd timer (alternativa moderna): # /etc/systemd/system/job.timer # [Timer] # OnCalendar=*:0/5
flock -n cria lock file — se já estiver a correr, não executa. Essencial para tarefas que demoram mais que o intervalo. Sem lock, múltiplas instâncias podem corromper dados. systemd timers são a alternativa moderna com melhor controlo.
Debugging e logs
# Verificar se o cron está activo: systemctl status cron pgrep cron # Logs em tempo real: tail -f /var/log/syslog | grep CRON # Testar expressão antes de agendar: # Use: crontab.guru (online) # Script de teste com timestamp: * * * * * echo "$(date): correu" >> /tmp/cron_test.log # Remover após confirmar: # crontab -e → apagar linha de teste
tail -f /var/log/syslog | grep CRON mostra execuções em tempo real. crontab.guru explica expressões visualmente. Para debug, agende * * * * * com echo e verifique o log. Problemas comuns: PATH errado e permissões.
Boas práticas
# 1. Caminhos absolutos SEMPRE 0 3 * * * /usr/bin/php /app/script.php # 2. Redireccionar output 0 3 * * * /script.sh >> /var/log/job.log 2>&1 # 3. Usar flock para tarefas longas */5 * * * * flock -n /tmp/j.lock /script.sh # 4. Comentar cada entrada # Backup diário da base de dados 30 2 * * * /scripts/backup.sh # 5. Testar o comando manualmente antes
Sempre use caminhos absolutos — o cron não herda o PATH. Redireccione output para logs. Use flock para evitar sobreposição. Comente cada job para manutenção futura. Teste o comando manualmente antes de agendar. Prefira scripts a comandos inline longos.