如何每 64 小时运行一次脚本?

Jef*_*rod 23 scripting cron

我需要每 64 小时运行一次脚本。我找不到答案cron。是否可以使用它,或者我应该在 shell 脚本中使用循环?

Sté*_*las 47

只需每小时运行一次,并检查自某个任意时刻(例如 Unix 纪元时间的时刻 0)以来的小时数是否为 64 的倍数:

0 * * * * t=$(date +\%s); [ "$(( (t / 3600) \% 64 ))" -eq 0 ] && your-command
Run Code Online (Sandbox Code Playgroud)

  • 也可以每 8 小时检查一次(24 和 64 的最大公因数) (16认同)
  • 还有一个问题是“date %s”给出的是 UTC 秒数,而“cron”则在本地时间运行。夏令时发生变化时,当地时间会被删除或添加一整小时。这在这里应该不是问题,因为脚本被称为“每小时”,但值得注意的是较长的间隔。 (8认同)
  • @somebody,我确实考虑过每 8 小时执行一次,但这在实施 DST 的区域设置中不起作用。例如在英国大陆,目前,冬季必须为“0 0,8,16 * * *”,夏季必须为“0 1,9,17 * * *”。 (7认同)
  • @Griffin,“crontab(5)”手册页在“LIMITATIONS”部分中有:*即使用户在其 crontab 中指定了 TZ 环境变量,这也只会影响 crontab 中执行的命令,而不影响 crontab 的执行任务本身。*。`date +%s` 本身与时区无关。 (2认同)

pol*_*mon 27

如果您是初学者,我建议也许使用 crontab“前端”(例如crontab.guru)来了解 crontab。

但是,正如您的情况一样,小时设置仅允许 0 到 23 之间的值,因此您不能在此处使用 crontab。

相反,我建议使用at. 在你的情况下,我可能会使用类似的东西:

at now + 64 hours
Run Code Online (Sandbox Code Playgroud)

然后输入您的命令或

echo "<your command>" | at now + 64 hours
Run Code Online (Sandbox Code Playgroud)

基本上,您将安排在上次调用该命令时立即运行该命令。另外,如果您不需要时间增量,而是想要确切的时间,我建议做一些时间算术,然后使用确切的时间来at运行命令。

我强烈建议阅读的手册页at,因为它相当全面。

  • 我建议在脚本的开头添加新的“at”调度,否则脚本执行期间的失败也将停止调度下一次运行。 (17认同)

Fel*_*xJN 26

cron用于按日期或时钟事件运行,即每月或每周的第一天或每天的每三个小时。

对于不能简单地用时钟时间或日期算术来表示的时间间隔运行的东西,我建议使用计时器systemd- 当然,只有当您systemd在各自的设备上运行时,它才有效。

您将需要两个文件:用于运行脚本的服务文件和用于管理事件的计时器文件。

$cat /etc/systemd/system/myscript.service

[Unit]
Description=this service runs my script

[Service]
ExecStart=/full/path/to/myscript.sh

#[Install]
#WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

该服务只是执行脚本而不检查它是否成功或其他任何内容。可以选择启用该服务,systemctl enable myscript.service这意味着它将在启动时执行一次 - 我对此进行了注释,因为计时器将处理启动事件。您可以通过手动运行脚本systemctl start myscript.service


$cat /etc/systemd/system/myscript.timer

[Unit]
Description=this timer runs myscript.service every 64h

[Timer]
OnBootSec=120
OnUnitActiveSec=64h


[Install]
WantedBy=timers.target
Run Code Online (Sandbox Code Playgroud)

这是自上次激活服务以来每 64 小时运行一次的计时器myscript.service,以及启动后两分钟运行一次的计时器(以确保系统处于服务运行的正确状态)。请注意,如果您重新启动/关闭电源,计时器将不会记住 64 小时。相应地启用并启动计时器:

systemctl enable myscript.timer
systemctl start myscript.timer
Run Code Online (Sandbox Code Playgroud)

由于计时器仅在启动后或自上次单元激活后启动,因此您必须运行该服务一次以确保计时器运行:

systemctl start myscript.service
Run Code Online (Sandbox Code Playgroud)

通过以下方式检查计时器的状态

systemctl list-timers
Run Code Online (Sandbox Code Playgroud)

  • 另外,使用固定的 120 秒计时器来尝试“确保系统处于正确的状态”是一个坏主意。将 [`After=`](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Before=) 与 [`Wants=`](https://www.freedesktop.org /software/systemd/man/systemd.unit.html#Wants=) 或 [`Requires=`](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Requires=)更明确地指定依赖项,以便您“知道”它们何时可用,而不是猜测 120 秒在所有情况下都足够了。 (2认同)

hob*_*bbs 6

64 小时等于 2 又 2/3 天,因此 3 * 64 小时 = 192 小时 = 8 天。所以你几乎可以做

0 0  1-25/8 * * foo
0 16 3-27/8 * * foo
0 8  6-30/8 * * foo
Run Code Online (Sandbox Code Playgroud)

除非你在月底得到一个简短的模式(如果该月有 30 天,那么 30 日 08:00 的跑步与 1 日 00:00 的跑步之间只有 16 个小时;如果该月有 31 天,则为 40 小时;如果该月有 28 天,则 27 日 16:00 运行与 1 日 00:00 运行之间为 32 小时;如果该月有 29 天天,则为 56),并且每当您所在地区进入夏令时或夏令时结束时(假设确实如此),时间都会关闭 1 小时。

不太符合您的规格(我赞同任何其他符合规格的答案),但这一个有趣的凑合练习。