如何通过 cronjob 每 45 天执行一次 shell 脚本?
答案1
如果您不需要正好 45 天,但“一个半月”就可以,那么一个简单的方法是每三个月在月初运行一次,并在每个月之后的下个月中旬运行一次。那些:
0 12 1 1,4,7,10 * /path/to/script
0 12 16 2,5,8,11 * /path/to/script
对于一般的任意间隔,其他答案显然更好,但 45 天听起来无论如何都是基于一个月的长度。人类用户也可能更习惯于月初或月中发生的事情,而不是每次都看到确切的日期漂移一两天。
答案2
由于 cron 不支持对该要求进行简单、直接的转换,因此我将使用时间戳文件和每日 cron 作业来处理它:
0 0 * * * /path/to/wrapper/script/below.sh
包装脚本:
#!/bin/bash
timestampfile=/var/run/this-job/timetampfile
# exit now if it hasn't been 45 days
((
$(date +%s) - $(stat -c %Z "$timestampfile")
<
(45 * 24 * 60 * 60)
)) && exit 0
touch "$timestampfile"
: run real script here
这会带来几个风险:
- 有人删除时间戳文件
- 有人触摸时间戳文件(无论好坏)
- 从 cron 作业条目中不明显看出实际脚本每 45 天运行一次
答案3
基于这个关于堆栈溢出的答案,您可以使用以下语法来完成此操作:
00 12 * * * test $(( $(date +\%s)/24/60/60\%45 )) = 20 && your_script
这项工作每天中午都会运行。然后,它计算从纪元开始的天数的模数,并测试它是否等于您指定的模数。在本例中,我指定了 20,这将使其在今天(2018-05-09 在 00:00 GMT 和 23:59 GMT 之间)评估为 true,然后从今天起 45 天,依此类推。您可以使用以下方法计算/测试下列的:
$ echo $(( $(date +%s)/24/60/60%45 ))
20
$ echo $(( $(date -d '+45 days' +%s)/24/60/60%45 ))
20
$ echo $(( $(date -d '+44 days' +%s)/24/60/60%45 ))
19
(请注意,如果您不在 UTC 时区,则可能需要考虑一天中的时间)。
答案4
crl
我在尝试发布使用时遇到了类似的问题OpenBSD 6.6
。使用以下脚本来安排下次启动的第一件事。
#!/bin/sh
# copy current crontab to file without launching script
/usr/bin/crontab -l | grep -v "/var/publishCRL.sh" > /var/tmpCron
# add entry for 45 days from now
# 45 days = 3888000 seconds
/bin/echo $(date -j -r `expr $(date +%s) + 3888000` "+%M %H %d %m")" * /var/publishCRL.sh" >> /var/tmpCron
# load edited crontab
/usr/bin/crontab /var/tmpCron
# cleanup
/bin/rm /var/tmpCron
# do CRL stuff