Come posso creare un cron job che esegue un'attività ogni tre settimane?


9

Ho un compito che deve essere eseguito sul programma del mio progetto (3 settimane).

Sono in grado di impostare cron per farlo ogni settimana o (ad esempio) la 3a settimana di ogni mese - ma non riesco a trovare un modo per farlo ogni tre settimane.

Potrei hackerare lo script per creare file temporanei (o simili) in modo che potesse funzionare era la terza volta che è stato eseguito, ma questa soluzione ha un odore.

Può essere fatto in modo pulito?


@itj 3 settimane = 21 giorni, quindi perché non inserire un'attività cron ogni 21 giorni?
Studente

1
@studer Potrei aver perso qualcosa, ma non pensavo che crontab fosse così flessibile
itj

Risposte:


8

Il file crontab consente solo di specificare:

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)

Quindi non è possibile specificare quali settimane devono essere applicate.

Scrivere uno script wrapper potrebbe essere l'opzione migliore.
È possibile ottenere il numero della settimana in uno script di shell utilizzando

date +%U

o

date +%V

a seconda che desideri che le tue settimane inizino la domenica o il lunedì.
Quindi potresti usare

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

E $ check sarebbe 0 nella prima, quarta, settima, ... settimana dell'anno.


3
Cosa succede alla fine dell'anno? Funzionerà più volte o salterà una settimana o qualcosa del genere, poiché un anno non si divide uniformemente in un multiplo di 3 settimane?
dav

Grazie per la risposta. Più pulito di qualsiasi idea avessi. È valido solo per 1 anno, ma dovrebbe essere OK per la maggior parte dei progetti.
itj

Per più anni, si otterrebbero due corse distanziate di 8 o 9 giorni tra Natale e il 1 ° gennaio, quindi è lì che dovresti farlo correttamente e registrare la "data dell'ultima corsa" da qualche parte in modo da poter calcolare una settimana di 3 intervallo.
njd,

3

Grazie a risposte precedenti, sono state indicate le opzioni di epoca come data -e o formattazione come% s

Anche se un po 'doloroso ((date +%s) / 86400)dà giorni dall'epoca.

Affidandosi al lavoro settimanale in esecuzione contemporaneamente, è quindi facile verificarlo in un giorno specifico di un periodo di 3 settimane ( $epoch_day%21 == 13ad esempio)

Nel mio caso, va bene, in quanto si tratta di un'attività a colpo singolo. Se viene perso in un determinato giorno, non è necessario correre alla prossima occasione.


1

Se è possibile salvare un file timestamp tra le esecuzioni, è possibile controllarne la data invece di basarsi esclusivamente sulla data corrente.

Se il tuo comando find supporta valori frazionari per -mtime(o ha -mmin) ( find di GNU ha entrambi , POSIX non sembra richiedere neanche uno ), potresti "limitare" i lavori cron con find e touch .

Oppure, se si dispone di un comando stat che supporta la visualizzazione delle date dei file come "secondi dall'epoca" (ad es. Stat da Gnu coreutils , anche altre implementazioni), è possibile effettuare il proprio confronto utilizzando date , stat e gli operatori di confronto della shell (insieme con tocco per aggiornare un file timestamp). Potresti anche essere in grado di usare ls invece di stat se può eseguire la formattazione (ad es . Ls da file GNU ).

Di seguito è riportato un programma Perl (l'ho chiamato n-hours-ago) che aggiorna un file timestamp ed esce correttamente se il timestamp originale era abbastanza vecchio. Il testo di utilizzo mostra come usarlo in una voce crontab per limitare un processo cron. Descrive inoltre le regolazioni per "l'ora legale" e come gestire i timestamp "in ritardo" delle corse precedenti.

#!/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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.