Comment puis-je créer un travail cron qui exécute une tâche toutes les trois semaines?

9

J'ai une tâche qui doit être effectuée sur le calendrier de mon projet (3 semaines).

Je peux configurer cron pour le faire chaque semaine, ou (par exemple) la 3e semaine de chaque mois - mais je ne trouve pas de moyen de le faire toutes les trois semaines.

Je pourrais pirater le script pour créer des fichiers temporaires (ou similaire) afin qu'il puisse fonctionner c'était la troisième fois qu'il était exécuté - mais cette solution sent.

Peut-il être fait de manière propre?

itj
la source
@itj 3 semaines = 21 jours alors pourquoi ne pas mettre une tâche cron tous les 21 jours?
Studer
1
@studer J'ai peut-être raté quelque chose, mais je ne pensais pas que crontab était aussi flexible
itj

Réponses:

8

Le fichier crontab vous permet uniquement de spécifier:

minute (0-59)
hour (0-23)
day of the month (1-31)
month of the year (1-12)
day of the week (0-6 with 0=Sunday)

Il n'est donc pas possible de spécifier les semaines à appliquer.

L'écriture d'un script wrapper peut être la meilleure option.
Vous pouvez obtenir le numéro de semaine dans un shell-script en utilisant

date +%U

ou

date +%V

selon que vous souhaitez que vos semaines commencent le dimanche ou le lundi.
Vous pouvez donc utiliser

week=$(date +%V)
check=$(( ($week - 1) % 3 ))

Et le chèque serait de 0 dans les 1ère, 4ème, 7ème, ... semaines de l'année.

njd
la source
3
Que se passe-t-il à la fin de l'année? Va-t-il courir des heures supplémentaires ou sauter une semaine ou quelque chose comme ça, car une année ne se divise pas également en un multiple de 3 semaines?
davr
Merci de répondre. Plus propre que n'importe quelle idée que j'avais. Ce n'est valable que pour 1 an - mais cela devrait être OK pour la plupart des projets.
itj
Sur plusieurs années, vous obtiendrez deux séries espacées de 8 ou 9 jours autour de Noël et du 1er janvier, c'est pourquoi vous devez le faire correctement et enregistrer la «dernière date d'exécution» quelque part afin de pouvoir calculer une période de 3 semaines intervalle.
njd
3

Grâce aux réponses précédentes, les options de l'époque ont été pointées pour dater -e ou formater en% s

Bien qu'un peu douloureux ((date +%s) / 86400)donne des jours de l'époque.

En s'appuyant sur le travail hebdomadaire exécuté en même temps, il est alors facile de comparer cela à un jour spécifique d'une période de 3 semaines ( $epoch_day%21 == 13par exemple)

Dans mon cas, c'est très bien, car c'est une tâche unique. Si elle est manquée le jour particulier, il n'est pas nécessaire de courir à la prochaine occasion.

itj
la source
1

Si vous pouvez enregistrer un fichier d'horodatage entre les exécutions, vous pouvez vérifier sa date au lieu de vous fier uniquement à la date actuelle.

Si votre commande find prend en charge des valeurs fractionnaires pour -mtime(ou a -mmin) ( GNU find a les deux , POSIX ne semble pas en avoir besoin non plus ), vous pouvez `` étrangler '' les tâches cron avec find et touch .

Ou, si vous avez une commande stat qui prend en charge l'affichage des dates de fichier en «secondes depuis l'époque» (par exemple, stat de Gnu coreutils , également d'autres implémentations), vous pouvez faire votre propre comparaison en utilisant date , stat et les opérateurs de comparaison du shell (avec avec touche pour mettre à jour un fichier d'horodatage). Vous pouvez également être en mesure d'utiliser ls au lieu de stat s'il peut effectuer le formatage (par exemple, ls de GNU fileutils ).

Ci-dessous se trouve un programme Perl (je l'ai appelé n-hours-ago) qui met à jour un fichier d'horodatage et se termine avec succès si l'horodatage d'origine était assez ancien. Son texte d'utilisation montre comment l'utiliser dans une entrée crontab pour limiter une tâche cron. Il décrit également les ajustements pour «l'heure d'été» et comment gérer les horodatages «tardifs» des exécutions précédentes.

#!/usr/bin/perl
use warnings;
use strict;
sub usage {
    printf STDERR <<EOU, $0;
usage: %s <hours> <file>

    If entry at pathname <file> was modified at least <hours> hours
    ago, update its modification time and exit with an exit code of
    0. Otherwise exit with a non-zero exit code.

    This command can be used to throttle crontab entries to periods
    that are not directly supported by cron.

        34 2 * * * /path/to/n-hours-ago 502.9 /path/to/timestamp && command

    If the period between checks is more than one "day", you might
    want to decrease your <hours> by 1 to account for short "days"
    due "daylight savings". As long as you only attempt to run it at
    most once an hour the adjustment will not affect your schedule.

    If there is a chance that the last successful run might have
    been launched later "than usual" (maybe due to high system
    load), you might want to decrease your <hours> a bit more.
    Subtract 0.1 to account for up to 6m delay. Subtract 0.02 to
    account for up to 1m12s delay. If you want "every other day" you
    might use <hours> of 47.9 or 47.98 instead of 48.

    You will want to combine the two reductions to accomodate the
    situation where the previous successful run was delayed a bit,
    it occured before a "jump forward" event, and the current date
    is after the "jump forward" event.

EOU
}

if (@ARGV != 2) { usage; die "incorrect number of arguments" }
my $hours = shift;
my $file = shift;

if (-e $file) {
    exit 1 if ((-M $file) * 24 < $hours);
} else {
    open my $fh, '>', $file or die "unable to create $file";
    close $fh;
}
utime undef, undef, $file or die "unable to update timestamp of $file";
exit 0;
Chris Johnsen
la source