Как я могу создать задание cron, которое запускает задание каждые три недели?

9

У меня есть задача, которую нужно выполнить в моем графике проекта (3 недели).

Я могу настроить cron, чтобы делать это каждую неделю или (например) на 3-й неделе каждого месяца - но не могу найти способ делать это каждые три недели.

Я мог взломать сценарий для создания временных файлов (или аналогичных), чтобы он мог сработать, это был третий раз, когда он был запущен - но это решение пахнет.

Можно ли это сделать чистым способом?

ITJ
источник
@itj 3 недели = 21 день, так почему бы не ставить задачу cron каждые 21 день?
Студер
1
@studer Я, возможно, что-то пропустил, но я не думал, что crontab был
настолько

Ответы:

8

Файл crontab позволяет только указать:

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)

Поэтому невозможно указать, какие недели должны применяться.

Написание сценария оболочки может быть лучшим вариантом.
Вы можете получить номер недели в shell-скрипте, используя

date +%U

или

date +%V

в зависимости от того, хотите ли вы, чтобы ваши недели начинались в воскресенье или в понедельник.
Так что вы могли бы использовать

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

И $ check будет 0 в 1, 4, 7, ... неделях года.

NJD
источник
3
Что происходит в конце года? Будет ли он работать больше раз или пропустить неделю или что-то еще, поскольку год не делится поровну на 3 недели?
2010 года
Спасибо за ответ. Точнее, чем у меня была идея. Это действительно только в течение 1 года - но это должно быть хорошо для большинства проектов.
2010 года
За несколько лет вы получите два прогона с интервалом в 8 или 9 дней между Рождеством и 1 января, поэтому вам нужно будет сделать это правильно и записать «дату последнего прогона» где-нибудь, чтобы можно было рассчитать 3-недельную интервал.
NJD
3

Благодаря более ранним ответам были указаны параметры эпохи для даты -e или форматирования как% s

Хотя немного больно ((date +%s) / 86400)дает дни из эпохи.

Опираясь на еженедельное выполнение задания в одно и то же время, легко проверить это по определенному дню в 3 недели ( $epoch_day%21 == 13например)

В моем случае это нормально, так как это одноразовая задача. Если он пропущен в определенный день, то нет необходимости использовать следующую возможность.

ITJ
источник
1

Если вы можете сохранить файл метки времени между запусками, вы можете проверить его дату, а не полагаться только на текущую дату.

Если ваша команда find поддерживает дробные значения для -mtime(или имеет -mmin) ( GNU find имеет оба , POSIX, похоже, не требует и того и другого ), вы можете «задушить» задания cron с помощью find и touch .

Или, если у вас есть команда stat, которая поддерживает отображение дат файлов как «секунд с начала эпохи» (например, stat из Gnu coreutils , а также других реализаций), вы можете сделать свое собственное сравнение, используя date , stat и операторы сравнения оболочки (вдоль с прикосновением, чтобы обновить файл метки времени). Вы также можете использовать ls вместо stat, если он может выполнять форматирование (например, ls из GNU fileutils ).

Ниже приведена программа на Perl (я ее так назвал n-hours-ago), которая обновляет файл отметки времени и успешно завершает свою работу, если исходная отметка времени была достаточно старой. Текст его использования показывает, как использовать его в записи crontab, чтобы ограничить работу cron. В нем также описываются корректировки для «летнего времени» и как обрабатывать «поздние» временные метки из предыдущих запусков.

#!/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;
Крис Джонсен
источник