Bagaimana saya bisa membuat pekerjaan cron yang menjalankan tugas setiap tiga minggu?

9

Saya memiliki tugas yang perlu dilakukan pada jadwal proyek saya (3 minggu).

Saya dapat mengatur cron untuk melakukan ini setiap minggu, atau (misalnya) pada minggu ke-3 setiap bulan - tetapi tidak dapat menemukan cara untuk melakukan ini setiap tiga minggu.

Saya bisa meretas skrip untuk membuat file sementara (atau yang serupa) sehingga bisa bekerja itu adalah ketiga kalinya dijalankan - tetapi solusi ini berbau.

Bisakah itu dilakukan dengan cara yang bersih?

itj
sumber
@ itj 3 minggu = 21 hari jadi mengapa tidak meletakkan tugas cron setiap 21 hari?
Studer
1
@ Studer Saya mungkin telah melewatkan sesuatu, tapi saya tidak berpikir crontab fleksibel
itj

Jawaban:

8

File crontab hanya memungkinkan Anda menentukan:

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)

Jadi tidak mungkin menentukan minggu mana yang akan berlaku.

Menulis skrip pembungkus mungkin merupakan pilihan terbaik.
Anda bisa mendapatkan nomor minggu dalam skrip shell dengan menggunakan

date +%U

atau

date +%V

tergantung pada apakah Anda ingin minggu Anda dimulai pada hari Minggu atau Senin.
Jadi bisa digunakan

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

Dan $ cek akan menjadi 0 pada minggu ke-1, ke-4, ke-7, tahun ini.

njd
sumber
3
Apa yang terjadi pada akhir tahun? Apakah akan berjalan ekstra kali atau melewati satu minggu atau sesuatu, karena satu tahun tidak dibagi secara merata menjadi kelipatan 3 minggu?
davr
Terima kasih atas jawabannya. Lebih rapi daripada ide yang saya miliki. Ini hanya berlaku untuk 1 tahun - tetapi itu harus OK untuk sebagian besar proyek.
itj
Selama beberapa tahun, Anda akan mendapatkan jarak dua kali lari 8 atau 9 hari sekitar Natal & 1 Januari, jadi saat itulah Anda harus melakukannya dengan benar dan mencatat "tanggal lari terakhir" di suatu tempat sehingga Anda dapat menghitung 3 minggu selang.
tgl
3

Berkat jawaban sebelumnya, telah diarahkan ke opsi zaman untuk tanggal -e atau memformat sebagai% s

Meskipun agak menyakitkan ((date +%s) / 86400)memberi hari dari zaman.

Mengandalkan pekerjaan mingguan yang dijalankan pada saat yang sama, maka mudah untuk memeriksa ini terhadap hari tertentu dari periode 3 minggu ( $epoch_day%21 == 13misalnya)

Dalam kasus saya ini baik-baik saja, karena ini adalah tugas satu tembakan. Jika terlewatkan pada hari tertentu maka tidak perlu berlari pada kesempatan berikutnya.

itj
sumber
1

Jika Anda dapat menyimpan file timestamp di antara proses, Anda dapat memeriksa tanggalnya alih-alih hanya mengandalkan tanggal saat ini.

Jika perintah find Anda mendukung nilai fraksional untuk -mtime(atau memiliki -mmin) ( find GNU memiliki keduanya , POSIX tampaknya tidak membutuhkan keduanya ), Anda dapat 'membatasi' tugas cron dengan find dan touch .

Atau, jika Anda memiliki perintah stat yang mendukung menampilkan tanggal file sebagai "detik sejak zaman" (mis. Stat dari Gnu coreutils , juga implementasi lainnya), Anda bisa membuat perbandingan sendiri menggunakan tanggal , stat , dan operator perbandingan shell (bersama dengan sentuhan untuk memperbarui file cap waktu). Anda juga mungkin dapat menggunakan ls alih-alih stat jika dapat melakukan format (mis. Ls dari GNU fileutils ).

Di bawah ini adalah program Perl (saya menyebutnya n-hours-ago) yang memperbarui file timestamp dan keluar dengan sukses jika cap waktu asli sudah cukup tua. Teks penggunaannya menunjukkan cara menggunakannya dalam entri crontab untuk mempercepat pekerjaan cron. Ini juga menjelaskan penyesuaian untuk "penghematan siang hari" dan bagaimana menangani cap waktu 'terlambat' dari proses sebelumnya.

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