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:
- Está mesmo registrado?
- De qual usuário é esse crontab?
- Há algum rastro de execução nos logs?
- Funciona quando executado à mão?
- 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
Um aviso antes de tudo: não execute crontab -r
O crontab -r apaga todo o crontab daquele usuário sem pedir confirmação.
Ele fica ao lado de crontab -e (editar) no teclado, o que torna "apaguei tudo por engano" um acidente clássico.
Não existe recurso embutido para recuperar o conteúdo apagado.
- Sempre guarde uma cópia antes de editar:
crontab -l > ~/crontab-$(date +%Y%m%d).bak - Para pausar uma tarefa, use
crontab -ee coloque um#no início da linha - Se realmente precisar apagar, use
crontab -i -r(o-ipede confirmação antes)
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.shnunca roda; tire a extensão e usebackup)
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 minutos0 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 -rsem 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 -lcontém a linha pretendida (para root, confira tambémsudo crontab -l) - [ ] Os logs (
grep CRON /var/log/syslogoujournalctl -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