我有一个任务需要按照我的项目计划(3 周)执行。
我可以设置计划任务每周或(例如)每月第三周执行此操作 - 但找不到每三周执行一次的方法。
我可以破解脚本来创建临时文件(或类似文件),这样它就可以算出这是第三次运行 - 但这个解决方案有问题。
可以以干净的方式完成吗?
答案1
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 在一年中的第 1、4、7 周... 将为 0。
答案2
感谢之前的回答,已经指出了纪元选项为 date -e 或格式化为 %s
虽然有点痛苦,但还是((date +%s) / 86400)
给了日子一个交代。
依靠同时运行的每周作业,可以很容易地根据 3 周期间的特定日期进行检查($epoch_day%21 == 13
例如)
对我来说,这没问题,因为这是一次性任务。如果在特定日期错过了,则无需在下次机会时运行。
答案3
如果您可以在运行之间保存时间戳文件,则可以检查其日期,而不仅仅依赖当前日期。
如果你的寻找命令支持分数值-mtime
(或有-mmin
)(GNU find 具有,POSIX 似乎不需要),你可以使用寻找和触碰。
或者,如果你有一个统计支持将文件日期显示为“纪元以来的秒数”的命令(例如统计来自 Gnu coreutils以及其他实现),你可以使用以下方法进行自己的比较:日期,统计以及 shell 的比较运算符(以及触碰更新时间戳文件)。您也可以使用ls代替统计如果它能够进行格式化(例如GNU fileutils 中的 ls)。
下面是一个 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;
答案4
现代的 crond 具有更多的灵活性。您的 cron 可能支持“/”斜线运算符,因此可以使用 */21 进行编程,以便每 21 天运行一次。
* * */21 * * /bin/dosomething.sh 2>&1 > /dev/null
它在我的系统上运行良好。