Por Que o cron Não Está Executando - Solução de Problemas do crontab no Linux

Por Que o cron Não Está Executando - Solução de Problemas do crontab no Linux

O que você vai conseguir fazer

  • Investigar em ordem por que uma tarefa cron não está executando
  • Ler e escrever os campos de agendamento de uma linha do crontab
  • Evitar as armadilhas clássicas de PATH, permissão e caminho relativo

Pré-requisitos (leia estes primeiro)

O Que Você Vai Aprender

  • Você investiga em ordem fixa por que uma tarefa cron "não está executando".
  • Você sabe onde estão os logs e como lê-los.
  • Você lê e escreve os campos de agendamento de uma linha do crontab.
  • Você evita as armadilhas de usuário, PATH e permissão que aparecem o tempo todo.

Resumo Rápido

Quando o cron não está funcionando, não conserte no feeling. Verifique nesta ordem:

  1. Está mesmo registrado?
  2. De qual usuário é esse crontab?
  3. Há algum rastro de execução nos logs?
  4. Funciona quando executado à mão?
  5. PATH / permissões / problemas do executável

Pré-requisitos

  • SO: Ubuntu
  • De iniciantes a profissionais em início de carreira
  • Cobre tanto root quanto usuários comuns

1. Tipos de cron (Entender Errado Aqui Trava Tudo)

Conclusão: cron de usuário, de root e /etc/cron.* rodam como usuários diferentes; saiba qual editou.

O Ubuntu tem mais de um cron.

Antes de tudo, os termos.

Termo Significado em uma linha Outros nomes que você verá
daemon Programa que roda em segundo plano, sem interface Também "processo residente" ou "serviço"
cron O daemon que executa comandos automaticamente em horários definidos Também "daemon cron" ou "crond"
crontab O arquivo com o agendamento e também o comando que o edita A mesma palavra para os dois sentidos
tarefa Uma linha agendada dentro do crontab Também "entrada" ou "job"
MTA O software responsável por enviar e-mails Postfix e sendmail são exemplos

1-1. cron de usuário

$ crontab -e
  • Executa como: aquele usuário
  • O mais usado no dia a dia

1-2. cron do root

$ sudo crontab -e
  • Executa como: root
  • Para tarefas que exigem privilégios

1-3. /etc/crontab e /etc/cron.d

São as definições de sistema. O formato tem seis campos: os cinco de agendamento são seguidos por uma coluna de usuário.

# min hora dia mes semana usuario comando
0     3    *   *   *      root    /usr/local/bin/backup.sh

Se escrever com cinco campos, como no crontab de usuário, o nome do comando é lido como nome de usuário. O log mostra algo como unknown user e nada executa. O formato depende de onde você escreve.

1-4. Diretórios como /etc/cron.daily

Scripts colocados em /etc/cron.hourly ou /etc/cron.daily são executados pelo run-parts, que impõe duas restrições.

  • O bit de execução é obrigatório (chmod +x)
  • Nome de arquivo com ponto e ignorado (backup.sh nunca roda; tire a extensão e use backup)

Deixe claro, antes de tudo, onde você escreveu a tarefa.

2. Escrevendo uma Linha do crontab (os Cinco Campos)

Conclusão: Os campos de agendamento são minuto, hora, dia, mês e dia da semana nessa ordem.

Uma linha do crontab de usuário (o que o crontab -e abre) tem cinco campos de "quando" mais o comando a executar. O /etc/crontab e o /etc/cron.d usam seis campos, como mostrado em 1-3 — não confunda os dois.

* * * * * comando
| | | | |
| | | | +-- Dia da semana (0-7, 0 e 7 = Domingo)
| | | +---- Mes (1-12)
| | +------ Dia (1-31)
| +-------- Hora (0-23)
+---------- Minuto (0-59)

O * significa "todos".

Exemplos:

  • 0 3 * * * - Todo dia às 3:00 da manha
  • */5 * * * * - A cada 5 minutos
  • 0 0 * * 0 - Todo domingo à meia-noite

Quando "dia do mês" e "dia da semana" recebem algo diferente de *, a tarefa roda quando qualquer um dos dois casar. 0 3 1 * 1 dispara no dia 1 de cada mês e toda segunda-feira. Para restringir a um deles, deixe o outro como *.

Dentro do comando de um crontab, um % sem escape é substituído por uma quebra de linha. Algo como date +%Y%m%d funciona no shell, mas quebra no instante em que você cola no crontab.

# Errado (tudo depois do % e cortado)
0 3 * * * /home/user/backup.sh >> /home/user/log/backup-$(date +%Y%m%d).log 2>&1

# Certo (escape com \%)
0 3 * * * /home/user/backup.sh >> /home/user/log/backup-$(date +\%Y\%m\%d).log 2>&1

Levar o tratamento da data para dentro do próprio script é uma saída igualmente confiável.

2-1. Confirme que a linha faz o que você quis

Em vez de registrar a carga real de imediato, comece com uma linha que só acrescenta date a cada minuto.

* * * * * /usr/bin/date >> /tmp/cron-test.log 2>&1

Espere alguns minutos; se /tmp/cron-test.log continuar crescendo, o cron em si está funcionando. Remova a linha quando terminar, ou o arquivo de log cresce para sempre.

3. Verifique Se Está Registrado

Conclusão: Use crontab -l e sudo crontab -l; "achei que tinha registrado" lidera a lista.

$ crontab -l
$ sudo crontab -l

O crontab -l apenas imprime o que está registrado. Ele não altera nada, então execute quantas vezes quiser.

"Achei que tinha registrado" é o acidente mais comum de todos.

4. Verificando Logs Quando Não Executa

Conclusão: Verifique logs via grep CRON /var/log/syslog ou journalctl -u cron para encontrar execuções.

4-1. Verificar logs do cron

$ grep CRON /var/log/syslog | tail -n 50
Dec 15 03:00:01 web01 CRON[2451]: (user) CMD (/home/user/backup.sh)
Dec 15 03:05:01 web01 CRON[2478]: (root) CMD (/usr/local/bin/cleanup.sh)

O (user) é o usuário que executou a tarefa, e o CMD (...) é o comando executado.

4-2. Acompanhamento de log em tempo real

$ tail -f /var/log/syslog | grep CRON

4-3. Usando journalctl

$ sudo journalctl -u cron -n 100

Sem rastro no log significa que nunca executou.

Em sistemas sem /var/log/syslog, use journalctl -u cron. Os dois comandos apenas exibem logs; nenhum altera a configuração do cron.

5. Quando Executa mas Falha

Conclusão: Uma linha CMD no log indica que o cron disparou; execute à mão como aquele usuário.

O log pode conter uma linha assim:

CMD (/path/to/script.sh)

Isso significa que o cron em si está funcionando.

O que fazer em seguida:

$ sudo -u <cron_user> /path/to/script.sh

Executar à mão realmente executa tudo o que o script faz. Se o script apaga arquivos ou atualiza dados, teste em um diretório descartável ou leia o conteúdo antes de rodar.

6. Armadilha #1: o PATH é Diferente

Conclusão: O PATH do cron é minúsculo; use caminhos completos ou defina PATH no topo do crontab.

O PATH do cron é extremamente curto. PATH é a lista de diretórios consultados quando você digita apenas o nome de um comando. O shell de login e o cron não compartilham a mesma lista.

Errado

mysqldump ...

Certo

/usr/bin/mysqldump ...

O which mostra o caminho completo.

$ which mysqldump
/usr/bin/mysqldump

Soluções:

  • Escreva caminhos completos
  • Defina o PATH no topo do crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

7. Armadilha #2: Sem Permissão de Execução

Conclusão: Permission denied indica falta do bit de execução; confira com ls -l e use chmod +x.

Permission denied

Verificar:

$ ls -l script.sh

Corrigir:

$ chmod +x script.sh

O chmod +x omite a quem se aplica, então normalmente concede execução a dono, grupo e outros de uma vez. Para conceder só a você, indique o alvo com chmod u+x script.sh.

8. Armadilha #3: Caminhos Relativos

Conclusão: O diretório de trabalho do cron não é fixo, então sempre use caminhos absolutos.

Com o cron, não dá para supor em qual diretório ele roda.

Errado

./script.sh

Certo

/home/user/script.sh

Caminhos relativos dentro do script falham pelo mesmo motivo. Torne absolutos também os caminhos usados no script.

9. Notificação por E-mail (Tornando as Falhas Visíveis)

Conclusão: MAILTO entrega a saída da tarefa; sem e-mail, falta MTA ou o cron nunca rodou.

O cron envia por e-mail qualquer saída que a tarefa produzir. Mensagens de erro também são saída, e é isso que torna o recurso útil para detectar falhas.

MAILTO=you@example.com

Se nenhum e-mail chegar:

  • Nenhum MTA está configurado
  • Ou o cron nunca executou

Onde o e-mail não é opção, gravar o resultado em arquivo é mais confiável.

0 3 * * * /home/user/backup.sh >> /home/user/log/backup.log 2>&1

O >> acrescenta e o 2>&1 manda a saída de erro para o mesmo arquivo.

Aponte a saída para um caminho onde o usuário que executa tenha permissão de escrita. Escrever em /var/log/ a partir do cron de um usuário comum falha com Permission denied, e o redirecionamento derruba a tarefa junto. Use /var/log/ apenas no cron do root, ou com um arquivo dedicado ao qual você já concedeu permissão de escrita.

10. Quando o cron é a Causa da Carga Pesada

Conclusão: Backups, compressão e rsync são os suspeitos habituais por trás de picos de I/O.

  • Backups
  • Compressão de logs
  • rsync
  • Limpeza do Docker

Verifique se o horário em que a carga subiu coincide com o horário dessas tarefas. A checagem mais rápida é journalctl -u cron --since "<horario>" para ver o rastro de execução.

Coisas a Evitar

  • Reescrever a tarefa antes de ler os logs
  • Colocar tudo no cron do root
  • Omitir caminhos completos
  • Pular o teste de execução manual
  • Executar crontab -r sem uma cópia de segurança

11. Checklist de Conclusão

Conclusão: Registro, rastro no log, destino da saída e cópia de segurança fecham a configuração.

  • [ ] O crontab -l contém a linha pretendida (para root, confira também sudo crontab -l)
  • [ ] Os logs (grep CRON /var/log/syslog ou journalctl -u cron) mostram rastro de execução
  • [ ] Todo caminho no comando e dentro do script é absoluto
  • [ ] Você recebe o resultado por arquivo ou por e-mail
  • [ ] Você guardou uma cópia do crontab anterior à edição

Resumo (Template para Copiar e Colar)

# Guardar copia (sempre, antes de editar)
crontab -l > ~/crontab-$(date +%Y%m%d).bak

# Verificar crontab
crontab -l
sudo crontab -l

# Visualizar logs
grep CRON /var/log/syslog
journalctl -u cron -n 100

# Executar a mao (como o usuario do cron)
sudo -u user /path/to/script.sh

Próximas Leituras