web-dev-qa-db-fra.com

Le travail Cron à exécuter le dernier jour du mois

Je dois créer un travail cron qui sera exécuté tous les derniers jours du mois. Je vais le créer à partir de cpanel.

Toute aide est appréciée. Merci

81
Utku Dalmaz

Le moyen le plus simple consiste peut-être simplement à effectuer trois tâches distinctes:

55 23 30 4,6,9,11        * myjob.sh
55 23 31 1,3,5,7,8,10,12 * myjob.sh
55 23 28 2               * myjob.sh

Cela se déroulera le 28 février, même les années bissextiles. Si cela pose un problème, vous devrez trouver un autre moyen.


Cependant, il est généralement beaucoup plus facile et correct d’exécuter le travail dès que possible le premier jour de chaque mois, avec quelque chose comme:

0 0 1 * * myjob.sh

et modifiez le script pour traiter les données du mois précédent .

Cela supprime les problèmes que vous pouvez rencontrer pour déterminer quel jour est le dernier jour du mois et garantit également que toutes les données de ce mois sont disponibles, dans l’hypothèse où vous les traitez. Si vous courez entre cinq heures et minuit le dernier jour du mois, vous risquez de manquer tout ce qui se passe entre cette heure et minuit.

C'est la façon habituelle de le faire de toute façon, pour la plupart des emplois de fin de mois.


Si vous voulez toujours vraiment le lancer le dernier jour du mois, vous pouvez simplement détecter si demain est le premier (dans le cadre de votre script, ou dans la crontab elle-même).

Donc, quelque chose comme:

55 23 28-31 * * [[ "$(date --date=tomorrow +\%d)" == "01" ]] && myjob.sh

cela devrait être un bon début, en supposant que vous ayez un programme date relativement intelligent.

Si votre programme date n'est pas assez avancé pour vous donner des dates relatives, vous pouvez juste mettre en place un programme très simple pour vous donner le jour du mois de demain (vous n'avez pas besoin du pleine puissance de date), telle que:

#include <stdio.h>
#include <time.h>

int main (void) {
    // Get today, somewhere around midday (no DST issues).

    time_t noonish = time (0);
    struct tm *localtm = localtime (&noonish);
    localtm->tm_hour = 12;

    // Add one day (86,400 seconds).

    noonish = mktime (localtm) + 86400;
    localtm = localtime (&noonish);

    // Output just day of month.

    printf ("%d\n", localtm->tm_mday);

    return 0;
}

et utilisez ensuite (en supposant que vous l'appeliez tomdom pour "le jour du mois de demain"):

55 23 28-31 * * [[ "$(tomdom)" == "1" ]] && myjob.sh

Bien que vous souhaitiez peut-être envisager d’ajouter une vérification d’erreur car time() et mktime() peuvent tous deux renvoyer -1 En cas de problème. Le code ci-dessus, pour des raisons de simplicité, n'en tient pas compte.

152
paxdiablo

Il existe une méthode légèrement plus courte qui peut être utilisée similaire à l'une des méthodes ci-dessus. C'est:

[ $(date -d +1day +%d) -eq 1 ] && echo "last day of month"

De plus, l'entrée de la crontab pourrait être mise à jour pour être vérifiée uniquement du 28 au 31 car il est inutile de l'exécuter les autres jours du mois. Ce qui vous donnerait:

0 23 28-31 * * [ $(date -d +1day +%d) -eq 1 ] && myscript.sh
46
Indie

Configurez une tâche cron à exécuter le premier jour du mois. Ensuite, modifiez l'horloge du système pour qu'elle soit un jour d'avance.

18
Tom Anderson

Qu'en est-il de celui-ci, après Wikipedia?

55 23 L * * /full/path/to/command
10
Piohen

En adaptant la solution de paxdiablo, je cours le 28 et le 29 février. Les données du 29ème écrasent le 28ème.

# min  hr  date     month          dow
  55   23  31     1,3,5,7,8,10,12   * /path/monthly_copy_data.sh
  55   23  30     4,6,9,11          * /path/monthly_copy_data.sh
  55   23  28,29  2                 * /path/monthly_copy_data.sh
10
Thunder Rabbit

Vous pouvez configurer un travail cron pour qu'il s'exécute tous les jours du mois et lui faire exécuter un script Shell comme suit. Ce script détermine si le nombre de jours de demain est inférieur à celui d’aujourd’hui (c’est-à-dire si demain est un nouveau mois), puis fait ce que vous voulez.

TODAY=`date +%d`
TOMORROW=`date +%d -d "1 day"`

# See if tomorrow's day is less than today's
if [ $TOMORROW -lt $TODAY ]; then
echo "This is the last day of the month"
# Do stuff...
fi
7
thomson_matt
#########################################################
# Memory Aid 
# environment    HOME=$HOME Shell=$Shell LOGNAME=$LOGNAME PATH=$PATH
#########################################################
#
# string         meaning
# ------         -------
# @reboot        Run once, at startup.
# @yearly        Run once a year, "0 0 1 1 *".
# @annually      (same as @yearly)
# @monthly       Run once a month, "0 0 1 * *".
# @weekly        Run once a week, "0 0 * * 0".
# @daily         Run once a day, "0 0 * * *".
# @midnight      (same as @daily)
# @hourly        Run once an hour, "0 * * * *".
#mm     hh      Mday    Mon     Dow     CMD # minute, hour, month-day month DayofW CMD
#........................................Minute of the hour
#|      .................................Hour in the day (0..23)
#|      |       .........................Day of month, 1..31 (mon,tue,wed)
#|      |       |       .................Month (1.12) Jan, Feb.. Dec
#|      |       |       |        ........day of the week 0-6  7==0
#|      |       |       |        |      |command to be executed
#V      V       V       V        V      V
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "Tomorrow is the first today now is  `date`" >> ~/message
1       0       1       *       *       rm -f ~/message
*       *       28-31   *       *       [ `date -d +'1 day' +\%d` -eq 1 ] && echo "HOME=$HOME LOGNAME=$LOGNAME Shell = $Shell PATH=$PATH" 
5
Leslie Satenstein

Certaines implémentations de cron supportent le drapeau "L" pour représenter le dernier jour du mois.

Si vous avez de la chance d'utiliser l'une de ces implémentations, c'est aussi simple que:

0 55 23 L * ?

Cela se déroulera à 23h55 le dernier jour de chaque mois.

http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger

5
Noah Heldman

Pour une méthode plus sûre dans une crontab basée sur la solution @Indie (utilisez le chemin absolu vers date + $() ne fonctionne pas sur tous les systèmes crontab):

0 23 28-31 * * [ `/bin/date -d +1day +\%d` -eq 1 ] && myscript.sh
5
zigarn
00 23 * * * [[ $(date +'%d') -eq $(cal | awk '!/^$/{ print $NF }' | tail -1) ]] && job

Découvrez un question connexe sur le forum unix.com.

4
rid

Pour l'implémentation d'AWS Cloudwatch cron (Scheduling Lambdas, etc.), cela fonctionne:

55 23 L * ? *

Courant à 23h55 le dernier jour de chaque mois.

4
Dan Herman

Vous pouvez simplement connecter toutes les réponses dans une ligne cron et utiliser uniquement la commande date.

Il suffit de vérifier la différence entre le jour du mois qui est aujourd'hui et demain:

0 23 * * * root [ $(expr $(date +\%d -d '1 days') - $(date +\%d)  ) -le 0 ]  && echo true

Si cette différence est inférieure à 0, cela signifie que nous changeons le mois et qu'il y a le dernier jour du mois.

3
Lukasz Stelmach

Et ça?

modifier l'utilisateur .bashprofile ajouter:

export LAST_DAY_OF_MONTH=$(cal | awk '!/^$/{ print $NF }' | tail -1)

Ajoutez ensuite cette entrée à crontab:

mm hh * * 1-7 [[ $(date +'%d') -eq $LAST_DAY_OF_MONTH ]] && /absolutepath/myscript.sh
2
Raul Baron
55 23 28-31 * * echo "[ $(date -d +1day +%d) -eq 1 ] && my.sh" | /bin/bash 
2
Donald Duck