Comando crontab: agendar tarefas sem falhas no Linux

Terminal com o comando crontab -e em destaque e a legenda «os 5 campos e a armadilha do PATH», da série Comandos Linux da HJFR

Há tarefas que ninguém devia fazer à mão: a cópia de segurança de madrugada, a verificação de cinco em cinco minutos, o relatório de segunda-feira. No Linux, quem as faz é o cron, e a forma de lhe dizer o quê e quando é o comando crontab. É a espinha dorsal da automação em qualquer servidor — e, por isso, um dos primeiros sítios onde um atacante tenta ficar.

Neste artigo vemos como listar e editar a tabela de tarefas, ler os cinco campos de tempo, evitar a armadilha do PATH, usar atalhos como @daily, controlar a saída com MAILTO e distinguir os crontabs do utilizador e do sistema. No fim, o ângulo de cibersegurança: persistência via cron e como auditar todos os crontabs.

Veja o guia em vídeo

Prefere ver antes de experimentar? No canal HJFR-IT no YouTube mostramos o crontab opção a opção, com o resultado de cada comando no ecrã — narrado em português e com legendas.

crontab — Guia Completo: agendar tarefas com o cron — canal HJFR-IT no YouTube. Se o áudio não arrancar em português, abra as definições do vídeo (ícone da roda dentada) → Faixa de áudio → Português.

O que faz o crontab

O cron é um serviço que acorda a cada minuto, consulta as tabelas de tarefas e executa as que coincidem com o momento atual. O crontab é o comando que gere essas tabelas: cada utilizador tem a sua, guardada em /var/spool/cron/crontabs/, e esse ficheiro nunca se edita à mão — usa-se sempre o crontab, que valida a sintaxe antes de instalar.

crontab -l              # listar
crontab -e              # editar (abre o $EDITOR)
crontab -r              # apagar tudo (cuidado!)
crontab -u UTIL -l      # crontab de outro utilizador (root)
crontab FICHEIRO        # instalar FICHEIRO como crontab

Cada linha é uma tarefa: cinco campos de tempo seguidos do comando. As linhas começadas por # são comentários e as do tipo NOME=valor definem variáveis de ambiente para as tarefas seguintes.

Listar e editar: crontab -l e crontab -e

O crontab -l (de list) mostra as tarefas agendadas — só leitura, sem risco. O crontab -e (de edit) abre a tabela no editor de $VISUAL ou $EDITOR; ao gravar e sair, verifica a sintaxe e instala a nova versão (crontab: installing new crontab), e o cron passa a respeitá-la sem reiniciar nada. Se houver um erro, recusa a instalação e pergunta se quer voltar a editar.

crontab -r: a letra ao lado que apaga tudo

No teclado, o r está ao lado do e, e o crontab -r apaga o crontab inteiro sem pedir confirmação e sem desfazer. Faça uma cópia antes de mexer e, em Debian e Ubuntu, prefira crontab -i -r, que pergunta antes de apagar. Para repor, passe o ficheiro ao crontab.

crontab -l > ~/cron.bak     # cópia de segurança
crontab -r                  # ...o acidente
crontab ~/cron.bak          # repor a partir da cópia

Os cinco campos de tempo

Aqui está o coração do crontab. Da esquerda para a direita: minuto (0–59), hora (0–23), dia do mês (1–31), mês (1–12) e dia da semana (0–7, em que o domingo é 0 ou 7). Meses e dias também aceitam nomes em inglês, como jan ou mon.

# .---------------- minuto (0 - 59)
# |  .------------- hora (0 - 23)
# |  |  .---------- dia do mês (1 - 31)
# |  |  |  .------- mês (1 - 12)
# |  |  |  |  .---- dia da semana (0 - 7; domingo = 0 ou 7)
# |  |  |  |  |
  *  *  *  *  *  comando a executar

Uma tarefa só corre quando todos os campos coincidem com o momento atual — exceto se restringir ao mesmo tempo o dia do mês e o dia da semana: aí basta um deles. Decorar a ordem é metade do caminho para dominar o cron.

Exemplos reais: asterisco, passos, listas e intervalos

  • * — qualquer valor. 0 3 * * * é minuto 0, hora 3, qualquer dia, mês e dia da semana: todos os dias às 03:00.
  • / — passos. */15 nos minutos é «a cada 15 minutos» (aos 00, 15, 30 e 45).
  • , — listas. 0 9,13,18 * * * corre às 09:00, às 13:00 e às 18:00.
  • - — intervalos. 1-5 no dia da semana é de segunda a sexta; com passo, 5-55/10 dá 5, 15, 25… até 55.
# às segundas-feiras, às 08:00
0 8 * * 1 /home/aluno/bin/relatorio.sh
# no dia 1 de cada mês, à meia-noite
0 0 1 * * /home/aluno/bin/arquivo-mensal.sh
# às 9, 13 e 18 horas, de segunda a sexta
0 9,13,18 * * 1-5 /home/aluno/bin/sync.sh

A armadilha do PATH que estraga a maioria dos jobs

Uma tarefa que funciona à mão pode falhar em silêncio no cron. A razão é o ambiente: o cron não lê o seu ~/.profile; corre os comandos com /bin/sh e um PATH mínimo, apenas /usr/bin:/bin. Se o script vive em ~/bin, a sua shell encontra-o; o cron não. O correio local mostra o erro e, nos cabeçalhos X-Cron-Env, o ambiente real:

Subject: Cron <aluno@hjfr> verificar.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/usr/bin:/bin>

/bin/sh: 1: verificar.sh: not found

A regra de ouro é usar sempre caminhos absolutos, para o comando e para os ficheiros que ele toca: não escreva verificar.sh, escreva /home/aluno/bin/verificar.sh. Como segunda defesa, defina um PATH explícito no topo do crontab — sem variáveis, porque ali não há expansão: PATH=$HOME/bin:$PATH não funciona.

PATH=/home/aluno/bin:/usr/local/bin:/usr/bin:/bin
*/15 * * * * /home/aluno/bin/verificar.sh

Atalhos e saída: @daily, @reboot e MAILTO

Atalhos legíveis

  • @hourly — a cada hora certa (o mesmo que 0 * * * *);
  • @daily — uma vez por dia, à meia-noite (0 0 * * *);
  • @weekly — ao domingo, à meia-noite (0 0 * * 0);
  • @reboot — uma vez, quando o cron arranca com a máquina; perfeito para iniciar algo depois de um reinício.

São mais legíveis, mas não escolhem a hora: para um backup às 03:00, escreva os cinco campos.

Saída, correio e ficheiros de registo

Por omissão, a saída e os erros de uma tarefa vão por email para o dono do crontab — raramente o que queremos. A variável MAILTO, no topo, diz para onde vão esses avisos (MAILTO="" desliga-os). Melhor ainda é redirecionar para um ficheiro de registo: >> acrescenta a saída e 2>&1 junta-lhe os erros. Assim, quando algo falha, sabe onde procurar.

MAILTO=ops@example.com
*/15 * * * * /home/aluno/bin/verificar.sh >> /home/aluno/logs/verificar.log 2>&1

Tipos de crontab: utilizador, root e sistema

  • De cada utilizador — editado com crontab -e, um ficheiro por utilizador em /var/spool/cron/crontabs/.
  • Do root — igual, mas com privilégios (sudo crontab -e). Com -u, o root lê ou edita o de qualquer utilizador: sudo crontab -l -u www-data.
  • Do sistema — o ficheiro /etc/crontab, a pasta /etc/cron.d/ e as pastas de scripts /etc/cron.daily/ e afins.

O crontab do sistema tem um campo a mais: o utilizador com que a tarefa corre, entre os horários e o comando. Edita-se diretamente, sem crontab -e.

# *  *  *  *  * user-name command to be executed
17 *  * * *  root  cd / && run-parts --report /etc/cron.hourly

Para tarefas de sistema, prefira um ficheiro próprio em /etc/cron.d/ ou um script em /etc/cron.daily/: é a forma limpa e moderna de os pacotes agendarem trabalho. Em Debian e Ubuntu, os ficheiros de /etc/cron.d/ com pontos no nome são ignorados.

crontab em cibersegurança

O cron é um mecanismo de persistência clássico. Depois de comprometer uma aplicação web, basta ao atacante uma linha para voltar sempre: um @reboot que relança o binário, ou um curl de hora a hora que o volta a descarregar. Uma conta de serviço como www-data com crontab é, só por si, um indício de comprometimento; com root, o alvo passa a ser /etc/cron.d/.

Auditar os crontabs de todos os utilizadores, não só o seu. Reveja /etc/crontab, /etc/cron.d/, as pastas cron.* e o spool, à procura de caminhos em /tmp ou /dev/shm, downloads e base64. As datas dos ficheiros dizem quando cada crontab foi instalado; o registo do cron, cada execução.

sudo ls -l /var/spool/cron/crontabs/
for u in $(cut -d: -f1 /etc/passwd); do
  sudo crontab -l -u "$u" 2>/dev/null | sed "s/^/$u: /"
done
sudo grep -rnE '/tmp/|/dev/shm|curl|wget|base64' /etc/crontab /etc/cron.d /var/spool/cron/crontabs | grep -v ':[0-9]*:#'
sudo journalctl -u cron --since today | grep CMD

Conter sem destruir evidência. Não apague a entrada maliciosa às cegas: mova os ficheiros para uma pasta de provas, preservando as datas. Retirá-la do cron impede que volte, mas o processo que já corre trata-se à parte. Em servidores sensíveis, limite o uso do crontab com /etc/cron.allow.

Experimente no simulador interativo

O simulador recria o crontab do utilizador aluno numa máquina fictícia, com o relógio parado em segunda-feira, 2 de novembro, às 08:58. À esquerda, cada linha é decomposta nos cinco campos, com as próximas execuções; abaixo, o registo do cron e os crontabs do sistema. Use sleep para fazer o tempo avançar: verá a verificação falhar pela armadilha do PATH e funcionar depois de corrigida. Demonstrar tudo percorre a sequência completa, Anterior e Seguinte navegam passo a passo e Repor estado volta ao início.

Erros comuns e boas práticas

  • Comandos sem caminho absoluto: o cron só tem PATH=/usr/bin:/bin. Escreva caminhos completos ou defina PATH no topo.
  • Carregar no -r em vez do -e: apaga tudo, sem pergunta. Faça crontab -l > ~/cron.bak antes de editar.
  • Deixar a saída ao deus-dará: sem redirecionamento, vai parar a um email que ninguém lê. Use >> ficheiro.log 2>&1 e defina MAILTO.
  • Esquecer o %: num crontab é fim de linha. Escape-o como \%, por exemplo em date +\%F.
  • Confundir o crontab do utilizador com o do sistema: em /etc/crontab e /etc/cron.d/ há um sexto campo, o utilizador; no crontab -e não há.

Conclusão

O crontab resume-se a poucas peças: -l e -e, os cinco campos, atalhos como @reboot, caminhos absolutos e a saída redirecionada para um registo. É o motor silencioso da automação em Linux — e, por isso mesmo, um sítio a vigiar. Para ler o registo do cron a fundo, veja o artigo sobre o journalctl; para tratar o processo que uma entrada maliciosa deixou a correr, o guia de kill e systemctl.

Workshop — Linha de Comandos Linux

Quer passar da leitura à prática, com exercícios reais e acompanhamento? No workshop Linha de Comandos Linux da HJFR trabalha estes e outros comandos da série — da administração do dia a dia à resposta a incidentes.

Este artigo faz parte da série «Comandos Linux, um a um» do blog HJFR — fique atento aos próximos comandos.