我想每 3 天执行一次 shell 脚本。使用 crontab 实际上01 00 */3 * *
无法满足条件,因为它会在 31 日运行,然后在每月 1 日再次运行。语法*/3
与 1,4,7 ... 25,28,31 相同。
应该有办法让脚本本身检查条件,如果 3 天未过就退出。因此 crontab 每天都会执行该脚本,但脚本本身会检查是否已过 3 天。
我甚至找到了一些代码,但它给了我语法错误,任何帮助都将不胜感激。
if (! (date("z") % 3)) {
exit;
}
main.sh: line 1: syntax error near unexpected token `"z"'
main.sh: line 1: `if (! (date("z") % 3)) {'
答案1
如果最后一次执行还未至少在特定时间之前,则要立即中止并退出脚本,您可以使用此方法,它需要一个存储上次执行日期和时间的外部文件。
将这些行添加到 Bash 脚本的顶部:
#!/bin/bash
# File that stores the last execution date in plain text:
datefile=/path/to/your/datefile
# Minimum delay between two script executions, in seconds.
seconds=$((60*60*24*3))
# Test if datefile exists and compare the difference between the stored date
# and now with the given minimum delay in seconds.
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test -f "$datefile" ; then
if test "$(($(date "+%s")-$(date -f "$datefile" "+%s")))" -lt "$seconds" ; then
echo "This script may not yet be started again."
exit 1
fi
fi
# Store the current date and time in datefile
date -R > "$datefile"
# Insert your normal script here:
不要忘记设置一个有意义的值,并根据您的需要datefile=
调整值(评估为 3 天)。seconds=
$((60*60*24*3))
如果您不想使用单独的文件,您也可以将上次执行时间存储在脚本的修改时间戳中。但这意味着对脚本文件进行任何更改都会重置 3 计数器,并被视为脚本已成功运行。
为了实现这一点,请将下面的代码片段添加到脚本文件的顶部:
#!/bin/bash
# Minimum delay between two script executions, in seconds.
seconds=$((60*60*24*3))
# Compare the difference between this script's modification time stamp
# and the current date with the given minimum delay in seconds.
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test "$(($(date "+%s")-$(date -r "$0" "+%s")))" -lt "$seconds" ; then
echo "This script may not yet be started again."
exit 1
fi
# Store the current date as modification time stamp of this script file
touch -m -- "$0"
# Insert your normal script here:
seconds=
再次,不要忘记根据您的需要调整值($((60*60*24*3))
评估为 3 天)。
答案2
Cron 确实不适合做这种事情。实际上,有一个常用但不太受欢迎的工具叫做在这可能会有用。主要设计用于交互式使用,我相信有人会找到更好的方法来实现这一点。
就我而言,我会将我正在运行的脚本列在 testjobs.txt 中,并包含一行内容。
举个例子,我将其命名为 testjobs.txt
echo "cat" >> foo.txt
date >> foo.txt
at now + 3 days < testjobs.txt
我有两个无辜的命令,它们可能是你的 shellscripts。我运行 echo 以确保我有一个确定的输出,并运行 date 以确认命令按需要运行。当 at 运行此命令时,它将通过在 3 天内向 at 添加新作业来完成。(我用一分钟测试 - 有效)
我很确定我会因为我滥用的方式而被人指责,但它是一个用于安排要运行的命令的方便工具在前一个命令之后的某个时间或 x 天。
答案3
首先,上面的代码片段是无效的 Bash 语法,看起来像 Perl。其次,参数z
todate
使其输出数字时区。+%j
是日期数。您需要:
if [[ ! $(( $(date +%j) % 3 )) ]] ;then
exit
fi
但年底你仍然会看到奇怪的事情:
$ for i in 364 365 1 ; do echo "Day $i, $(( $i % 3 ))"; done
Day 364, 1
Day 365, 2
Day 1, 1
您可能更愿意将计数保存在文件中,然后对其进行测试/更新。
答案4
您可以使用 anacron 代替 cron,它专为满足您的需要而设计。摘自手册页:
Anacron 可用于定期执行命令,频率以天为单位。与 cron(8) 不同,它不假设机器连续运行。因此,它可以用于不是全天 24 小时运行的机器,以控制通常由 cron 控制的每日、每周和每月作业。
执行时,Anacron 会从配置文件(通常是 /etc/anacrontab,请参阅 anacrontab(5))中读取作业列表。此文件包含 Anacron 控制的作业列表。每个作业条目指定一个以天为单位的时间段、以分钟为单位的延迟、唯一的作业标识符和一个 shell 命令。
对于每个作业,Anacron 都会检查该作业是否在过去 n 天内执行过,其中 n 是该作业指定的时间段。如果没有,Anacron 会在等待延迟参数指定的分钟数后运行该作业的 shell 命令。
命令退出后,Anacron 会将日期记录在该作业的特殊时间戳文件中,以便它知道何时再次执行该作业。仅使用日期进行时间计算。不使用小时。