¿Cómo puedo crear un trabajo cron que ejecute una tarea cada tres semanas?

9

Tengo una tarea que debo realizar en el cronograma de mi proyecto (3 semanas).

Puedo configurar cron para hacer esto cada semana, o (por ejemplo) en la tercera semana de cada mes, pero no puedo encontrar una manera de hacerlo cada tres semanas.

Podría hackear el script para crear archivos temporales (o similares) para que pudiera funcionar, era la tercera vez que se ejecutaba, pero esta solución huele mal.

¿Se puede hacer de manera limpia?

itj
fuente
@itj 3 semanas = 21 días, entonces ¿por qué no poner una tarea cron cada 21 días?
Studer
1
@studer que puede haber perdido algo, pero no pensé que era crontab flexibles
itj

Respuestas:

8

El archivo crontab solo le permite especificar:

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)

Por lo tanto, no es posible especificar qué semanas deberían aplicarse.

Escribir un script de envoltura puede ser la mejor opción.
Puede obtener el número de semana en un script de shell utilizando

date +%U

o

date +%V

dependiendo de si desea que sus semanas comiencen el domingo o el lunes.
Entonces podrías usar

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

Y $ check sería 0 en la 1ra, 4ta, 7ma, ... semanas del año.

njd
fuente
3
¿Qué pasa a fin de año? ¿Funcionará más veces o se saltará una semana o algo así, ya que un año no se divide de manera uniforme en un múltiplo de 3 semanas?
davr
Gracias por responder. Más limpio que cualquier idea que tuviera. Solo es válido por 1 año, pero eso debería estar bien para la mayoría de los proyectos.
itj
A lo largo de varios años, obtendría dos carreras espaciadas con 8 o 9 días de diferencia entre Navidad y el 1 de enero, por lo que necesitaría hacerlo correctamente y registrar la "última fecha de ejecución" en algún lugar para poder calcular un período de 3 semanas. intervalo.
njd
3

Gracias a las respuestas anteriores, se han señalado las opciones de época para fechar -e o formatear como% s

Aunque un poco doloroso ((date +%s) / 86400)da días desde la época.

Confiando en el trabajo semanal que se ejecuta al mismo tiempo, es fácil verificar esto contra un día específico de un período de 3 semanas ( $epoch_day%21 == 13por ejemplo)

En mi caso, esto está bien, ya que es una tarea de un solo disparo. Si se pierde en un día en particular, no hay necesidad de correr en la próxima oportunidad.

itj
fuente
1

Si puede guardar un archivo de marca de tiempo entre ejecuciones, puede verificar la fecha en lugar de confiar únicamente en la fecha actual.

Si su comando find admite valores fraccionarios para -mtime(o tiene -mmin) ( GNU find tiene ambos , POSIX no parece requerir ninguno de los dos ), podría 'estrangular' los trabajos cron con find y touch .

O bien, si tiene un comando stat que admite mostrar fechas de archivo como "segundos desde la época" (por ejemplo, stat de Gnu coreutils , también otras implementaciones), puede hacer su propia comparación usando date , stat y los operadores de comparación del shell (junto con con toque para actualizar un archivo de marca de tiempo). También puede usar ls en lugar de stat si puede formatear (por ejemplo, ls de GNU fileutils ).

A continuación se muestra un programa Perl (lo llamé n-hours-ago) que actualiza un archivo de marca de tiempo y se cierra con éxito si la marca de tiempo original era lo suficientemente antigua. Su texto de uso muestra cómo usarlo en una entrada crontab para acelerar un trabajo cron. También describe los ajustes para el "horario de verano" y cómo manejar las marcas de tiempo "tardías" de las ejecuciones anteriores.

#!/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
fuente