【问题标题】:Runt a bash script every 10 seconds between certain hours在特定小时之间每 10 秒运行一次 bash 脚本
【发布时间】:2020-06-07 12:16:36
【问题描述】:

我有一个每 5 秒运行一次的脚本,是否可以在例如 CET 08:00 - 12:00 之间运行此脚本?

我以为我可以通过 cron 作业来完成这项工作,但不幸的是,这至少需要 1 分钟。所以我正在考虑创建一个 cron 作业,它在 08:00 启动脚本,然后在 12:00 终止它,我认为这是最好的解决方案。

有人有意见吗?

    #!/bin/bash

while true; do
    python3 script.py
    sleep 5;
done

【问题讨论】:

  • 这能回答你的问题吗? Cron jobs -- to run every 5 seconds
  • 这将在每次调用之前等待 N 秒,这将偏离真正的 N 秒周期。那么应该是N 秒间隔 还是 N 秒?
  • 我认为相隔 N 秒没关系,如果我正确理解了您的问题。运行脚本,等待 5 秒,然后再次运行。这就是我想要实现的目标:)

标签: python-3.x bash shell


【解决方案1】:

正如Wiimm 指出的那样,他的回答仅涵盖“运行脚本,等待 10 秒并在 8:00 到 12:00 之间重复”。

我能想到几种方法:

A.在 cron 中在 8:00 启动脚本并让它检查何时完成

#!/bin/sh

END=$(date -d "12:00" +"%H * 60 + %M" | bc)

while [ $(date +"%H * 60 + %M" | bc) -lt $END ]; do
    date >> /tmp/log.txt # replace this with your script 
    sleep 10
done

解释:

  • date +"%H * 60 + %M" | bc 计算自一天开始以来的分钟数。 注意:此处使用 bc 处理前导零 $(( $(date +"%H * 60 + %M") )) 会出错。
  • [ $(date +"%H * 60 + %M" | bc) -lt $END ] - 与结束时间比较

B.从 cron 启动它并使用信号处理程序来处理优雅退出,使用 cron 来结束它。

#!/bin/bash

echo $$ > /tmp/pid.txt
EXIT=
trap "echo 'Exiting' >> /tmp/log.txt; EXIT=yes" TERM

while [[ -z "$EXIT" ]]; do
    date >> /tmp/log.txt # replace this with your script
    sleep 10
done

crontab 看起来像这样:

00 08 * * * /path/to/wrappers/script.sh
00 12 * * * kill $(cat /tmp/pid.txt)

解释:

  • echo $$ > /tmp/pid.txt - 保存 pid(你应该选择 另一个位置,适合您的系统)
  • trap "echo 'Exiting' >> /tmp/log.txt; EXIT=yes" TERM - 这将在 TERM 时运行 echo 'Exiting' >> /tmp/log.txt; EXIT=yes 接收到信号(TERM 是 kill 发送的默认信号)。
  • while [[ -z "$EXIT" ]]; do - EXIT 为空时重复
  • 这样做的好处是能够在需要时优雅地关闭脚本,而不仅仅是在 12:00。

注意:两者结合可能是最好的方法。

另外:请参阅https://stackoverflow.com/a/53561843/939457 - 它详细说明了如何通过 SystemD 运行它,但即使之前的脚本没有结束,它也会每 10 秒运行一次脚本(如果我理解答案的话正确,我不熟悉 SystemD)

【讨论】:

  • Cron 或 anacron 确实是唯一好的解决方案:理想情况下,bash 不应该处理这个问题。 Cron 仅用于在特定时间安排任务并可靠地执行此操作。让它完成它的工作,然后让脚本只包含它需要的功能。
  • @AlexanderHuszagh - cron 没有 10 秒的分辨率,并且在之前的运行结束 10 秒后将无法运行脚本
  • 这里的job不是每10秒执行一次,而是每10秒执行一次加上执行命令所需的时间。请参阅我的答案以获取 sleep 10 的替代方案。
  • @Sorin Title 说:“每 10 秒运行一次”。并且不要将我的评论+答案视为批评者,将其视为注释/想法,以替代按标题满足请求的方法。我赞成您的解决方案,因为我喜欢它。
【解决方案2】:

除了索林的解决方案。

while true; do
  do_something 
  sleep 10
done

这里的作业 do_something 不是 (!) 每 10 秒执行一次,而是每 10 秒执行一次,加上执行 do_something 所需的时间。所以另一种选择是:

while true; do
  sleep $((10-$(date +%s)%10))
  do_something 
done

这里每次执行作业do_something,当秒是0、10、20、30、40或50之一。唯一的陷阱:如果do_something运行模式超过10秒,至少执行一次跳过。

我的睡眠解释:

DELAY=10
sleep $(( DELAY- $(date +%s) % DELAY))

$((...)) 进入数学模式。 $(date +%s) 返回自纪元以来的总秒数。 % DELAY 是一个模运算,因此结果介于 0 和不包括 DELAY(本例中为 0..9)之间。 DELAY- 保证睡眠时间至少为 1 秒。

【讨论】:

  • $SECONDS 在 bash 中有特殊的含义(其实我也不确定是不是只有 bash,但我没时间查):"每次这个参数被引用,则返回自 shell 调用以来的秒数。如果为 SECONDS 分配了值,则后续引用时返回的值是自分配以来的秒数加上分配的值。如果未设置 SECONDS,它将失去其特殊属性,即使它随后被重置。"您可能想为您的示例考虑一个不同的名称,或者使用它来发挥您的优势
  • @Sorin:感谢您的提示。我知道,但在写解释时不要考虑它。但是我的示例会起作用,因为 SECONDS 的本地定义会覆盖 bash 的特殊含义。无论如何,我现在将其替换为 DELAY 以避免混淆。
  • ideone.com/pPSPoy - 您必须明确取消设置 SECONDS 才能使其工作
  • 尝试 echo $SECONDS; sleep $(( 10 - $SECONDS % 10 )); echo $SECONDS 或在 new shell 中类似 while true; do SECONDS=0; sleep $(( $RANDOM % 4 + 1)) ; echo $SECONDS; sleep $((10 - $SECONDS)); echo $SECONDS; done - 我查了一下,似乎 posix sh 没有它
猜你喜欢
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 2016-07-24
  • 2021-05-04
  • 2016-04-27
  • 1970-01-01
相关资源
最近更新 更多