Como ler uma expressão cron
Uma expressão cron são cinco valores separados por espaços, lidos da esquerda para a direita como minuto, hora, dia do mês, mês e dia da semana. A tarefa corre quando a hora atual corresponde a todos os campos.
30 4 * * 1
│ │ │ │ │
│ │ │ │ └── day of week (1 = Monday)
│ │ │ └──── month (any)
│ │ └────── day of month (any)
│ └──────── hour (4am)
└─────────── minute (30)
Esta lê-se "às 04:30 de todas as segundas-feiras".
Os cinco campos
| # | Campo | Valores permitidos | Notas |
|---|---|---|---|
| 1 | Minuto | 0 a 59 | |
| 2 | Hora | 0 a 23 | Relógio de 24 horas, 0 é meia-noite |
| 3 | Dia do mês | 1 a 31 | |
| 4 | Mês | 1 a 12, ou JAN a DEC | |
| 5 | Dia da semana | 0 a 6, ou SUN a SAT | 0 é domingo, e a maioria das implementações de cron também aceita 7 |
Alguns agendadores usam outro formato. O Quartz, usado por muito software Java, põe os segundos à frente e acrescenta um ano opcional, e numera os dias da semana de 1 a 7 a começar no domingo. Se uma expressão tiver seis ou sete campos, verifique para que sistema foi escrita antes de confiar na sua leitura.
Os operadores
São quatro, e combinam-se dentro de um mesmo campo.
| Símbolo | Nome | Exemplo | Significado |
|---|---|---|---|
* | Qualquer | * * * * * | Todos os minutos de todos os dias |
, | Lista | 0 9,13,17 * * * | Às 09:00, às 13:00 e às 17:00 |
- | Intervalo | 0 9-17 * * * | De hora a hora, das 09:00 às 17:00 inclusive |
/ | Passo | */15 * * * * | Aos :00, :15, :30 e :45 |
Um passo aplica-se sempre a um intervalo. */15 no campo dos minutos significa "a começar em 0, tomar cada 15.º valor até 59". Também se pode aplicar um passo a um intervalo explícito: 5-30/10 dá 5, 15 e 25, e depois para porque 35 já passou o fim.
Os passos não significam "de 15 em 15 minutos a partir de agora"; selecionam valores fixos do relógio. */40 dispara aos :00 e aos :40 e depois espera apenas 20 minutos pelos :00 da hora seguinte, porque a contagem recomeça a cada hora. As listas podem conter intervalos e passos, por isso 0 0-6/2,12,18-23 * * * é um campo de hora válido.
Nomes e atalhos
Os campos do mês e do dia da semana aceitam nomes de três letras, e a caixa não conta, por isso JAN, jan e Jan são a mesma coisa. A documentação clássica do crontab diz que intervalos e listas de nomes não são permitidos, embora muitas implementações modernas aceitem MON-FRI. Se não tiver a certeza de quem executa a sua tarefa, use números: 1-5 é inequívoco em todo o lado.
Vários atalhos substituem a expressão de cinco campos por inteiro:
| Atalho | Equivalente | Corre |
|---|---|---|
@yearly ou @annually | 0 0 1 1 * | À meia-noite de 1 de janeiro |
@monthly | 0 0 1 * * | À meia-noite do dia 1 de cada mês |
@weekly | 0 0 * * 0 | À meia-noite de domingo |
@daily ou @midnight | 0 0 * * * | À meia-noite, todos os dias |
@hourly | 0 * * * * | À hora certa |
Também existe @reboot, mas não é um horário: corre a tarefa uma vez quando o próprio cron arranca.
A armadilha do dia do mês e do dia da semana
É esta que morde. Quando tanto o campo do dia do mês como o campo do dia da semana estão restringidos, ou seja, nenhum deles é *, o cron corre a tarefa quando qualquer um dos dois corresponde, e não quando os dois correspondem.
0 0 13 * 5
Isso pode ler-se como "à meia-noite da sexta-feira 13". O que significa na realidade é "à meia-noite do dia 13 de cada mês e também à meia-noite de todas as sextas-feiras": mais de sessenta execuções por ano em vez de uma ou duas.
O comportamento de E que esperava só se aplica quando um dos dois campos é *. Assim, 0 0 * * 5 é todas as sextas-feiras e 0 0 13 * * é todos os dias 13, ambos perfeitamente normais. É restringir os dois que desencadeia o OU.
Não há forma normalizada de exprimir "sexta-feira 13" em cinco campos. O contorno habitual é agendar para todos os dias 13 e fazer com que a tarefa verifique o dia da semana antes de fazer seja o que for.
Uma subtileza relacionada: algumas implementações decidem se um campo está restringido verificando se ele começa literalmente por *. Nessas, 0-6 no campo do dia da semana conta como restringido, mesmo cobrindo todos os dias, ligando discretamente o comportamento de OU. Use * quando quiser dizer "qualquer".
Erros que vale a pena procurar
* */2 * * *corre a cada minuto durante uma hora sim, outra não: 720 execuções por dia. O que queria era0 */2 * * *, que dá 12.- Um campo de minuto em falta desloca tudo uma posição para a esquerda e normalmente continua a ser lido sem erro, dando-lhe um horário válido a uma hora completamente errada.
0 0 31 * *salta em silêncio os meses que não têm dia 31.- O cron usa o fuso horário do sistema ou do utilizador, a não ser que o agendador lhe permita definir um. Quando os relógios mudam para a hora de verão, uma tarefa colocada na hora saltada pode não correr de todo e uma colocada na hora repetida pode correr duas vezes, consoante a implementação. As tarefas que têm de correr uma vez por dia ficam mais seguras se forem agendadas longe da madrugada em que a mudança acontece.
Na dúvida, leia a expressão em voz alta como uma frase e verifique depois as próximas vezes em que ela dispararia de facto. Se essas datas não forem as que descreveu, a expressão é que está errada, não a sua leitura.