web-dev-qa-db-fra.com

Comment planifier l'exécution du premier dimanche de chaque mois

J'utilise Bash sur RedHat. Je dois planifier un travail cron à 9 h 00 le premier dimanche de chaque mois. Comment puis-je faire ceci?

49
ring bearer

Vous pouvez mettre quelque chose comme ça dans le fichier crontab:

00 09 * * 7 [ $(date +\%d) -le 07 ] && /run/your/script

Le date +%d vous donne le numéro du jour en cours, puis vous pouvez vérifier si le jour est inférieur ou égal à 7. Si tel est le cas, exécutez votre commande.

Si vous exécutez ce script uniquement le dimanche, cela signifie qu'il ne s'exécute que le premier dimanche du mois.

N'oubliez pas que dans le fichier crontab, les options de formatage de la commande date doivent être échappées.

130
Lukasz Stelmach

Vous devez combiner deux approches:

a) Utilisez cron pour exécuter un travail tous les dimanches à 9h00.

 00 09 * * 7     /usr/local/bin/once_a_week

b) Au début de once_a_week, calcule la date et extrait le jour du mois via Shell, Python, C/C++, ... et teste entre 1 et 7 inclus. Si oui, exécutez le vrai script; sinon, sortez en silence.

12
Dirk Eddelbuettel

Il convient de noter que ce qui ressemble à l'approche la plus évidente de ce problème ne fonctionne pas .

Vous pourriez penser que vous pourriez simplement écrire une entrée crontab qui spécifie le jour de la semaine comme 0 (pour dimanche) et le jour du mois comme 1-7, comme ceci ...

# This does NOT work.
0 9 1-7 * 0 /path/to/your/script

... mais, en raison de ne excentricité de la façon dont Cron gère les lignes crontab avec un jour de la semaine et un jour du mois spécifié , cela ne fonctionnera pas, et fonctionnera en fait sur les 1er, 2e, 3e, 4e, 5e, 6e et 7e du mois (quel que soit le jour de la semaine où ils se trouvent) et le tous les dimanches du mois.

C'est pourquoi vous voyez la recommandation d'utiliser un [ ... ] vérifiez avec date pour configurer une règle comme celle-ci - soit en spécifiant le jour de la semaine dans la crontab et en utilisant [ et date pour vérifier que le jour du mois est <= 7 avant d'exécuter le script, comme indiqué dans le réponse acceptée , ou en spécifiant la plage de jours du mois dans la crontab et en utilisant [ et date pour vérifier le jour de la semaine avant de lancer, comme ceci:

# This DOES work.
0 9 1-7 * * [ $(date +\%u) = 7 ] && /path/to/your/script

Quelques bonnes pratiques à garder à l'esprit si vous souhaitez vous assurer que votre ligne crontab fonctionnera quel que soit sous quel OS vous l'utilisez:

  • Utilisation =, ne pas ==, pour la comparaison. C'est plus portable, car tous les shells n'utilisent pas une implémentation de [ qui prend en charge le == opérateur.
  • Utilisez le %u spécificateur à date pour obtenir le jour de la semaine sous forme de nombre, pas le %a, car %a donne des résultats différents selon les paramètres régionaux date est en cours d'exécution.
  • Utilisez simplement date, pas /bin/date ou /usr/bin/date, car l'utilitaire date a des emplacements différents sur différents systèmes.
6
Mark Amery

Une solution hacky: exécutez votre tâche cron tous les dimanches, mais demandez à votre script de vérifier la date au début et de quitter immédiatement si le jour du mois est> 7 ...

5
thesunneversets

Exécuter une tâche cron 1er lundi, 3ème mardi, dernier dimanche, n'importe quoi ..

http://xr09.github.io/cron-last-sunday/

Mettez simplement le run-if-today script dans le chemin d'accès et utilisez-le avec cron.

30 6 * * 6 root run-if-today 1 Sat && /root/myfirstsaturdaybackup.sh

Le run-if-today le script ne renverra 0 (valeur bash pour True) que si c'est la bonne date.

MODIFIER:

Maintenant, avec une interface plus simple, un seul paramètre pour le numéro de semaine.

# run every first saturday
30 6 * * 6 root run-if-today 1 && /root/myfirstsaturdaybackup.sh

# run every last sunday
30 6 * * 7 root run-if-today L && /root/lastsunday.sh
5
MGP

Cela fonctionne également avec les noms des jours de la semaine:

0 0 1-7 * * [ "$(date '+\%a')" == "Sun" ] && /usr/local/bin/urscript.sh

Mais,

[ "$(date '+\%a')" == "Sun" ] && echo SUNDAY

[~ # ~] échouera [~ # ~] sur comandline en raison du traitement spécial de "%" dans crontab (également valable pour https://stackoverflow.com/a/3242169/2919695 )

4
maniac_on_moon

Si vous ne voulez pas que cron exécute votre travail tous les jours ou tous les dimanches, vous pouvez écrire un wrapper qui exécutera votre code, déterminer le premier premier dimanche suivant et se planifier pour s'exécuter à cette date.

Planifiez ensuite cet emballage pour le premier premier dimanche du mois. Après cela, il gérera tout lui-même.

Le code serait quelque chose comme (accent sur quelque chose ... aucune vérification d'erreur effectuée):

#! /bin/bash
#We run your code first
/path/to/your/code
#now we find the next day we want to run
nskip=28 #the number of days we want to check into the future
curr_month=`date +"%m"`
new_month=`date --date='$nskip days' +"%m"`
if [[ curr_month = new_month ]] 
then
((nskip+=7))
fi
date=`date --date='$nskip days' +"09:00AM %D` #you may need to change the format if you use another scheduler
#schedule the job using "at"
at -m $date < /path/to/wrapper/code

La logique est simple pour trouver le premier premier dimanche suivant. Puisque nous commençons le premier dimanche du mois en cours, l'ajout de 28 nous placera soit le dernier dimanche du mois en cours, soit le premier dimanche du mois suivant. S'il s'agit du mois en cours, nous passons au dimanche suivant (qui sera dans la première semaine du mois suivant).

Et j'ai utilisé "at". Je ne sais pas si c'est de la triche. L'idée principale est de trouver le premier premier dimanche suivant. Vous pouvez ensuite remplacer le planificateur de votre choix, car vous connaissez la date et l'heure auxquelles vous souhaitez exécuter le travail (un planificateur différent peut cependant avoir besoin d'une syntaxe différente pour la date).

0
user390948

peut-être utiliser cron.hourly pour appeler un autre script. Ce script vérifiera ensuite si c'est le premier dimanche du mois et 9h du matin, et si c'est le cas, exécutez votre programme. Cela me semble assez optimal :-).

0
gtrak