Comment puis-je dire à cron d'exécuter une commande tous les deux jours (impair / pair)

45

Lors de la configuration de cron pour exécuter une commande tous les deux jours à l'aide du champ "Jour du mois", procédez comme suit:

1 22 */2 * * COMMAND

il fonctionne chaque fois que le jour du mois est impair: 1,3,5,7,9 et ainsi de suite.

Comment puis-je configurer cron pour qu'il fonctionne les jours du mois qui sont même comme 2,6,8,10 et ainsi de suite (sans le préciser, ce qui est problématique car chaque mois a un nombre de jours différent du mois)?

Freddie
la source

Réponses:

60

La syntaxe que vous avez essayée est en réalité ambiguë. En fonction du nombre de jours dans le mois, certains mois, les jours impairs et les jours pairs. En effet, la manière dont il est calculé prend le nombre total de possibilités et les divise. Vous pouvez contourner ce comportement aléatoire en spécifiant manuellement la plage de jours et en utilisant un nombre de jours impair ou pair. Comme les scripts de jour même ne fonctionneraient jamais le 31e jour de mois plus longs, vous ne perdez rien en utilisant 30 jours comme base, et en spécifiant spécifiquement de le diviser comme s'il y avait 31 jours, vous pouvez forcer des impairs. exécution d'un jour.

La syntaxe ressemblerait à ceci:

# Will only run on odd days:
0 0 1-31/2 * * command

# Will only run on even days:
0 0 2-30/2 * * command

Votre préoccupation concernant les mois n'ayant pas le même nombre de jours n'est pas importante ici car aucun mois n'a PLUS de jours que celui-ci et pour un mois de février médiocre, la plage de dates ne correspondra jamais au dernier jour ou aux deux derniers jours, mais elle ne fera aucun mal à il a énuméré.

Le seul 'acquis' pour cette approche est que si vous êtes sur un cycle de jours impairs, les mois suivants avec 31 jours, votre commande sera également exécutée le premier du mois. De même, si vous forcez un cycle pair, chaque année bissextile entraîne un cycle de trois jours et la fin du mois de février. Vous ne pouvez vraiment pas oublier le fait qu’un schéma régulier de "tous les jours" ne va pas toujours tomber les jours pairs ou impairs tous les mois et quelle que soit la façon dont vous le forcerez, vous ferez un essai supplémentaire ou manquerez un essai entre mois avec des jours mal appariés compte.

Caleb
la source
1
Merci, mais que se passera-t-il des mois comme février où vous ne disposez que de 28 jours? La star s’occupe de cela, mais elle est ambiguë.
Freddie
3
@freddie: Voir ma réponse corrigée ... mais ce n'est pas un problème, car les valeurs hors limites seront simplement ignorées, rien ne se passera le 30 ou le 31 février. Déjà. Vous pouvez spécifier manuellement avec une liste comme quoi 0,2,4...,30,32,34et peu importait, les valeurs hors limites ne seraient jamais mises en correspondance.
Caleb
1
Merci! Je comprends, merci pour la réponse informative!
Freddie
3
Sur le serveur Ubuntu 8.04, il semble que la syntaxe utilisant le jour du mois zéro soit invalide (mauvais jour du mois). La syntaxe suivante est cependant acceptée:0 0 2-30/2 * * command
1
Fedora et RHEL 5,6,7 n’aiment pas non plus 0 comme jour du mois. Comme l’a souligné user31053: 0 0 2-30/2 * * commandfonctionne comme prévu.
NoelProf
2

Je pense qu'une possibilité utilise le jour de l'année, comme celui-ci:

# for odd days
test $(((`date +%j` % 2))) != 0 && command

# for even days
test $(((`date +%j` % 2))) == 0 && command

Il est testé pour les systèmes Unix et Linux.

Jordi
la source
Je préfère cette réponse car elle évite le problème du nombre impair de jours à quelques mois. Quoi qu'il en soit, je suggère la notation en dollars à la place des pièces arrière:test $(($(date +%j) % 2)) == 0 && command
caligari le
J'ai noté que% j n'est pas la date du calendrier julien. Le meilleur code évitant la transition du Nouvel An doit donc être calculé en secondes:test $(($(date +%s) / 86400 % 2)) == 0 && command
caligari le
Merci pour les commentaires! Notre proposition a fonctionné pour nous comme un charme. Nous avons utilisé ce schéma pour exécuter tous les jours des tâches sur différents nœuds de serveur, partageant la même crontab, mais le script ne permettant d'exécuter le script que sur l'un d'entre eux. Toutefois, si nous devons la préciser, nous examinerons votre proposition. Merci!!!
Jordi
1

Vérifions chaque jour s'il s'agit d'un "autre" :-) ( bcprogramme requis)

0 0 * * * test $(echo `date +%s` / 86400 % 2 == 0 |bc) -eq 0 && command

(Je ne suis pas sûr que le code apparaisse correctement. La date +%spartie se situe entre les apostrophes arrière.)

utilisateur37264
la source
Cela fonctionnera tous les deux jours mais ne répond pas à la question! Il fonctionnera encore parfois des jours impairs, parfois des jours pairs, selon le mois. Cela a le même résultat que le code dans la question, vous arrivez juste au résultat en faisant vos propres calculs sur les secondes depuis l'époque. Cela fonctionne les jours pairs depuis l'époque mais pas les jours pairs de notre calendrier.
Caleb
1

En général, je l'utilisais tous les jours et le script utilisait la logique pour déterminer s'il devait être exécuté aujourd'hui.

Créer un simple fichier de statut indiquant la dernière exécution, puis la comparaison fonctionnerait très facilement.

Si vous devez utiliser différentes sources, faites-le dépendre des arguments.

Klas Mattsson
la source