【发布时间】:2011-03-15 12:59:06
【问题描述】:
我在 RedHat 上使用 Bash。我需要安排一个 cron 作业在每个月的第一个星期日上午 9:00 运行。我该怎么做?
【问题讨论】:
我在 RedHat 上使用 Bash。我需要安排一个 cron 作业在每个月的第一个星期日上午 9:00 运行。我该怎么做?
【问题讨论】:
您可以在crontab 文件中添加这样的内容:
00 09 * * 7 [ $(date +\%d) -le 07 ] && /run/your/script
date +%d 为您提供当天的编号,然后您可以检查该天是否小于或等于 7。如果是,请运行您的命令。
如果您只在星期日运行此脚本,则应该意味着它只在每月的第一个星期日运行。
请记住,在 crontab 文件中,date 命令的格式选项应该被转义。
【讨论】:
-le 的东西记录在哪里?我需要为第 1 个星期日、第 2 个星期日、第 3 个星期日、第 4 个星期日和(也许)第 5 个星期日做同样的事情......
test 命令相同(这些是这些命令的快捷方式):linux.die.net/man/1/test
值得注意的是,看起来最明显的解决此问题的方法不起作用。
您可能认为您可以只编写一个 crontab 条目,将星期几指定为 0(表示星期日),将月份指定为 1-7,如下所示...
# This does NOT work.
0 9 1-7 * 0 /path/to/your/script
...但是,由于an eccentricity of how Cron handles crontab lines with both a day-of-week and day-of-month specified,这将不起作用,实际上会在每月的 1 号、2 号、3 号、4 号、5 号、6 号和 7 号运行(无论是哪一天)他们所在的星期)和在每个月的每个星期日。
这就是为什么您看到建议使用 [ ... ] 检查和 date 来设置这样的规则 - 在 crontab 中指定星期几并使用 [ 和 date在运行脚本之前检查月份是否为 accepted answer 所示,或在 crontab 中指定月份范围并使用 [ 和 date 来检查日期运行前一周,如下所示:
# This DOES work.
0 9 1-7 * * [ $(date +\%u) = 7 ] && /path/to/your/script
如果您想确保您的 crontab 行无论您使用的是什么操作系统,请记住一些最佳实践:
=,而不是==,进行比较。它更便携,因为并非所有 shell 都使用支持 == 运算符的 [ 实现。%u 说明符到date 将星期几作为数字,而不是%a 运算符,因为%a 会根据运行date 的语言环境给出不同的结果.date,而不是/bin/date 或/usr/bin/date,因为date 实用程序在不同系统上的位置不同。【讨论】:
您需要结合两种方法:
a) 使用cron 在每周日上午 9:00 运行作业。
00 09 * * 7 /usr/local/bin/once_a_week
b) 在once_a_week 的开头,通过shell、Python、C/C++、...计算日期并提取月份中的某天,并测试1 到7 之间(含)。如果是,执行真正的脚本;如果没有,请静默退出。
【讨论】:
man 5 crontab 所说的那样工作 day of week 0-7 (0 or 7 is Sun, or use names)
一个 hacky 解决方案:让您的 cron 作业每周日运行,但让您的脚本在开始时检查日期,如果当月的日期大于 7 则立即退出...
【讨论】:
这也适用于工作日的名称:
0 0 1-7 * * [ "$(date '+\%a')" == "Sun" ] && /usr/local/bin/urscript.sh
但是,
[ "$(date '+\%a')" == "Sun" ] && echo SUNDAY
由于在 crontab 中对“%”的特殊处理,将在命令行上FAIL(也适用于https://stackoverflow.com/a/3242169/2919695)
【讨论】:
%a 输出特定于语言环境的字符串)。它也不能移植到其他 Unix,其中 /bin/sh 是一个带有 [ 实现的 shell,不支持 == 运算符(例如 Ubuntu,其中 /bin/sh 是 Dash)。
在第 1 个星期一、第 3 个星期二、上个星期日等任何时间运行一个 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
【讨论】:
也许使用 cron.hourly 来调用另一个脚本。然后该脚本将检查它是否是该月的第一个星期日和上午 9 点,如果是,则运行您的程序。听起来对我来说足够理想:-)。
【讨论】:
如果您不希望 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”。我不知道这算不算作弊。主要想法是找到下一个第一个星期日。之后您可以替换任何您想要的调度程序,因为您知道要运行作业的日期和时间(不过,不同的调度程序可能需要不同的日期语法)。
【讨论】:
试试下面的
0 15 10 ? * 1#1
http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
【讨论】:
? 语法不是常规 Unix Cron 的一部分。它是 Quartz Scheduler 中语法的扩展。
00 09 1-7 * 0 /usr/local/bin/once_a_week
每月前 7 天的每个星期日
【讨论】: