Como instruir o cron para executar um trabalho a cada segunda semana?

Eu gostaria de executar um trabalho através do cron que será executado a cada segunda terça-feira a determinada hora do dia. Para toda terça-feira é fácil:

0 6 * * Tue 

Mas como fazer isso em “toda segunda terça” (ou se você preferir – a cada segunda semana)? Eu não gostaria de implementar qualquer lógica no próprio script, mas manter a definição apenas no cron.

Que tal isso, ele mantém no crontab mesmo que não seja exatamente definido nos cinco primeiros campos:

 0 6 * * Tue expr `date +\%W` \% 2 > /dev/null || /scripts/fortnightly.sh 

Responda

Modifique sua lógica cron de terça-feira para executar a cada duas semanas desde a época .

Sabendo que existem 604800 segundos em uma semana (ignorando mudanças de horário de verão e saltos segundos, obrigado), e usando a data do GNU:

 0 6 * * Tue expr `date +\%s` / 604800 \% 2 >/dev/null || /scripts/fortnightly.sh 

a parte, de lado

Aritmética de calendar é frustrante.

A resposta de @ xahtep é ótima, mas, como observou @Doppelganger nos comentários , ela falhará em certos limites do ano. Nenhum dos especificadores de “semana do ano” do utilitário de date pode ajudar aqui. Alguma terça-feira no início de janeiro irá inevitavelmente repetir a paridade da semana da terça-feira final do ano anterior: 2016-01-05 (% V), 2018-01-02 (% U) e 2019-01-01 (% W) .

A resposta de pilcrow é ótima. No entanto, isso faz com que o script quinzenal.sh seja executado a cada semana (desde a época). Se você precisar que o script seja executado em semanas ímpares , você pode ajustar a resposta dele um pouco:

 0 6 * * Tue expr \( `date +\%s` / 604800 + 1 \) \% 2 > /dev/null || /scripts/fortnightly.sh 

Mudando o 1 para 0, ele volta para semanas pares.

Talvez um pouco idiota, mas também é possível criar dois cronjobs, um para cada terça-feira e um para cada terceiro.

Primeiro cronjob:

 0 0 8 ? 1/1 TUE#1 * 

Segundo cronjob:

 0 0 8 ? 1/1 TUE#3 * 

Não tenho certeza sobre a syntax aqui, usei o http://www.cronmaker.com/ para fazer isso.

E a cada 3 semanas?

Aqui está minha sugestão:

 0 6 * * Tue expr `date +\%W` \% 3 == 0 > /dev/null || /scripts/fortnightly.sh 

… ou …

 0 6 * * Tue expr `date +\%W` \% 3 == 1 > /dev/null || /scripts/fortnightly.sh 

… ou claro …

 0 6 * * Tue expr `date +\%W` \% 3 == 2 > /dev/null || /scripts/fortnightly.sh 

… dependendo da rotação da semana.

Se você quiser que todas as terças-feiras da segunda semana apenas:

00 06 * * 2 # 2

Eu descobri algumas limitações adicionais de abordagens acima que podem falhar em alguns casos extremos. Por exemplo, considere:

@xahtep e @Doppelganger discutiram questões usando %W em certos limites do ano acima.

@ resposta de pilcrow contorna isso em algum grau, no entanto, também irá falhar em certos limites. As respostas neste e em outros tópicos relacionados usam o número de segundos em um dia (versus semana), que também falham em determinados limites pelas mesmas razões.

Isso ocorre porque essas abordagens dependem da hora UTC (data +% s). Considere um caso em que estamos fazendo um trabalho às 01:00 e 22:00 toda segunda terça-feira.

Suponha que o GMT-2:

  • 1h, hora local = 11h UTC de ontem
  • 10pm hora local = 8pm UTC hoje

Se estivermos verificando apenas uma única vez todos os dias, isso não será um problema, mas, se estivermos verificando várias vezes, ou se estivermos próximos da hora UTC e do horário de verão, o script não consideraria esses dados mesmo dia.

Para contornar isso, precisamos calcular um deslocamento de UTC com base em nosso fuso horário local e não em UTC. Não consegui encontrar uma maneira simples de fazer isso no BASH, então desenvolvi uma solução que usa um liner rápido em Perl para calcular o deslocamento do UTC em segundos.

Esse script aproveita a data +% z, que gera o fuso horário local.

Script de bash:

 TZ_OFFSET=$( date +%z | perl -ne '$_ =~ /([+-])(\d{2})(\d{2})/; print eval($1."60**2") * ($2 + $3/60);' ) DAY_PARITY=$(( ( `date +%s` + ${TZ_OFFSET} ) / 86400 % 2 )) 

depois, para determinar se o dia é par ou ímpar:

 if [ ${DAY_PARITY} -eq 1 ]; then ... else ... fi 

Cron fornece uma syntax “todos os outros” “/ 2”. Basta seguir o campo apropriado da unidade de tempo com “/ 2” e ele executará o cronjob “a cada outra hora”. No seu caso…

 0 6 * * Tue/2 

O acima deve executar todas as outras terças-feiras.

A syntax “/ 2” não é compatível com o dia da semana. Então, meu adicionado ao smart acima é simplesmente usar 1,15 no MonthDay arquivado.

0 6 1,15 * * /scripts/fornightly.sh> / dev / null 2> & 1

Por que não algo como

 0 0 1-7,15-21,29-31 * 5 

Isso é apropriado?

    Intereting Posts