70

我在 RedHat 上使用 Bash。我需要安排一个 cron 作业在每个月的第一个星期日上午 9:00 运行。我怎样才能做到这一点?

4

10 回答 10

168

您可以在crontab文件中添加以下内容:

00 09 * * 7 [ $(date +\%d) -le 07 ] && /run/your/script

为您提供当天的date +%d编号,然后您可以检查当天是否小于或等于 7。如果是,请运行您的命令。

如果您仅在星期日运行此脚本,则应该意味着它仅在该月的第一个星期日运行。

请记住,在crontab文件中,命令的格式选项date应该被转义。

于 2010-07-13T22:49:50.357 回答
22

值得注意的是,看起来最明显的解决这个问题的方法是行不通的。

您可能认为您可以只编写一个 crontab 条目,将星期几指定为 0(代表星期日),将月份指定为 1-7,如下所示...

# This does NOT work.
0 9 1-7 * 0 /path/to/your/script

...但是,由于Cron 处理带有指定日期和日期的 crontab 行的古怪方式,这将不起作用,实际上将在 1 日、2 日、3 日运行,每月的 4 号、5 号、6 号和 7 号(无论是星期几)每月的每个星期日。

这就是为什么您会看到建议使用[ ... ]检查date来设置这样的规则 - 在 crontab 中指定星期几并[date运行脚本,如接受的答案所示,或在 crontab 中指定月份范围,并在运行前使用[anddate来检查星期几,如下所示:

# This DOES work.
0 9 1-7 * * [ $(date +\%u) = 7 ] && /path/to/your/script

如果您想确保您的 crontab 行无论您在什么操作系统上使用它都能正常工作,请记住一些最佳实践:

  • 使用=, not==进行比较。它更便携,因为并非所有 shell 都使用[支持==操作符的实现。
  • 使用说明%u符将date星期几作为数字而不是%a运算符获取,因为%a根据date运行的语言环境会给出不同的结果。
  • 只需使用date, not /bin/dateor /usr/bin/date,因为该date实用程序在不同系统上有不同的位置。
于 2018-07-14T21:55:38.040 回答
14

您需要结合两种方法:

a) 用于cron每周日上午 9:00 运行作业。

 00 09 * * 7     /usr/local/bin/once_a_week

b) 在开始时once_a_week,通过 shell、Python、C/C++、... 计算日期并提取月份中的日期,并测试 1 到 7 之间的值,包括 1 到 7。如果是,执行真正的脚本;如果没有,请默默退出。

于 2010-07-13T20:34:15.970 回答
6

一个 hacky 解决方案:让您的 cron 作业每周日运行,但让您的脚本在开始时检查日期,如果当月的日期大于 7,则立即退出...

于 2010-07-13T20:32:18.803 回答
5

这也适用于工作日的名称:

0 0 1-7 * * [ "$(date '+\%a')" == "Sun" ] && /usr/local/bin/urscript.sh

但,

[ "$(date '+\%a')" == "Sun" ] && echo SUNDAY

由于 crontab 中对“%”的特殊处理,将在命令行上失败(也适用于https://stackoverflow.com/a/3242169/2919695

于 2013-10-25T11:28:25.867 回答
5

在第一个星期一,第三个星期二,上个星期日,任何事情上运行一个 cron 任务。

http://xr09.github.io/cron-last-sunday/

只需将run-if-today脚本放在路径中并与 cron 一起使用即可。

30 6 * * 6 root run-if-today 1 Sat && /root/myfirstsaturdaybackup.sh

如果日期正确,run-if-today脚本只会返回 0(True 的 bash 值)。

编辑:

现在界面更简单,周数只有一个参数。

# run every first saturday
30 6 * * 6 root run-if-today 1 && /root/myfirstsaturdaybackup.sh

# run every last sunday
30 6 * * 7 root run-if-today L && /root/lastsunday.sh
于 2014-03-31T15:06:29.203 回答
0

也许使用 cron.hourly 来调用另一个脚本。然后该脚本将检查它是否是该月的第一个星期日和上午 9 点,如果是,则运行您的程序。对我来说听起来足够优化:-)。

于 2010-07-13T20:17:25.433 回答
0

如果您不希望 cron 每天或每个星期天运行您的工作,您可以编写一个包装器来运行您的代码,确定下一个星期天,并安排自己在该日期运行。

然后将该包装器安排在本月的下一个第一个星期日。之后它将自己处理所有事情。

代码将类似于(强调某事......没有进行错误检查):

#! /bin/bash
#We run your code first
/path/to/your/code
#now we find the next day we want to run
nskip=28 #the number of days we want to check into the future
curr_month=`date +"%m"`
new_month=`date --date='$nskip days' +"%m"`
if [[ curr_month = new_month ]] 
then
((nskip+=7))
fi
date=`date --date='$nskip days' +"09:00AM %D` #you may need to change the format if you use another scheduler
#schedule the job using "at"
at -m $date < /path/to/wrapper/code

找到下一个第一个星期日的逻辑很简单。由于我们从当月的第一个星期日开始,加上 28 将使我们成为当月的最后一个星期日或下个月的第一个星期日。如果是当前月份,我们会递增到下一个星期日(即下个月的第一周)。

我用了“at”。我不知道这算不算作弊。主要想法是找到下一个第一个星期日。之后您可以替换您想要的任何调度程序,因为您知道要运行作业的日期和时间(不过,不同的调度程序可能需要不同的日期语法)。

于 2010-07-15T19:00:26.420 回答
-1

尝试以下

0 15 10 ? * 1#1

http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger

于 2015-10-14T08:32:23.660 回答
-3

00 09 1-7 * 0 /usr/local/bin/once_a_week

每月前 7 天的每个星期日

于 2013-04-18T06:59:19.127 回答