【问题标题】:Cron jobs and random times, within given hours给定时间内的 Cron 作业和随机时间
【发布时间】:2012-02-21 09:30:54
【问题描述】:

我需要能够在完全随机的时间每天运行 20 次 PHP 脚本。我还希望它只在上午 9 点到晚上 11 点之间运行。

我熟悉在 linux 中创建 cron 作业。

【问题讨论】:

  • 这个问题不是很好。最终,您希望在上午 9 点到 11 点之间的时间轴上分配 20 个点。但是最小时差有限制吗?早上 9 点到 10 点 30 分之间什么都不做可以接受吗?在 Klaus 的想法看来,唯一可以接受的方法是:在 09:00 选择您的 20 次,这样您就可以满足您可能遇到的任何限制,然后用“at”安排事情。

标签: bash cron sh


【解决方案1】:

我意识到这是一个较旧的线程,但我想添加一个我经常使用的与随机值相关的东西。我经常在 shell 中创建任意范围的随机值,而不是使用具有固定和有限范围的 $RANDOM 变量

dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none

所以你可以这样做,例如,

FULLRANDOM=$(dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none)

并克服此线程中讨论的一些限制。

【讨论】:

  • 欢迎来到 SO。好吧,不管旧线程与否,这让我去了~$info dd,我可以理解| 左侧发生了什么,但无法识别右侧。所以,对于我和其他对随机值生成中的overcoming some restrictions 感兴趣的人,为什么不花点时间解释一下 RHS,并为使用你的方法做出更强有力的宣传。解释的深度使人们对您建议的过程及其好处感到满意。谢谢。
  • 嗯,好的。 od aka“八进制转储”采用文件或标准输入并以人类可读的形式转储二进制数据。我们希望我们的数字显示为无符号十进制(-t u4),并且不希望地址索引(-A none)。 -N4 是多余的,因为我们只占用 4 个字节,但也没有什么坏处。我希望这能解释它......
【解决方案2】:

创建一个每天重写 crontab 的脚本怎么样?

  1. 读取当前 crons (A)
  2. 选择随机时间 (B)
  3. 重写之前的 crons (A),添加新的随机 crons (B)
  4. 确保首先添加到 cron 以运行此脚本。

【讨论】:

  • 不要通过发布 cmets 作为答案来规避信誉系统。但是,您的 comment 看起来确实足以成为 一个答案。我建议删除“我没有代表添加评论,但是”。
  • 我刚刚查看了这个答案,并错过了你最后提出问题的部分(我的工作很草率)。不要在答案中提问。针对您有的问题发布您自己的问题。我把你的半问题变成了可以作为答案的东西。
  • 知道了!谢谢。下次我会更加小心,没有恶意。
  • 我确定您没有恶意,也无需过于小心。您概述了一个可能的解决方案 - 最后偶然发现了一点。不用担心!
【解决方案3】:

您可以尝试使用此示例在执行命令之前使用随机时间:

#!/bin/bash
# start time
date +"%H:%M:%S"

# sleep for 5 seconds
sleep $(shuf -i 1-25 -n 1)
# end time
date +"%H:%M:%S"

【讨论】:

    【解决方案4】:

    al-x 的解决方案对我不起作用,因为 crontab 命令不是在 bash 中执行,而是在 sh 我猜。起作用的是:

    30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
    

    【讨论】:

    • 我尝试了所有方法,但它仍然不适合我。您的帖子解释了原因,谢谢!
    • $[ ... ] 是不推荐使用的语法,因为 waaaay 回来了;对于这个千年以来的任何东西,你会更喜欢$((RANDOM\%90))m,它是与 POSIX 兼容的语法(但当然RANDOM 仍然只是 Bash)。
    【解决方案5】:

    我最终使用了sleep $(( 1$(date +%N) % 60 )) ; dostuffs(兼容 bash 和 sh)

    1 前缀是强制对日期 +%N 进行 NON base 8 解释(例如 00551454)

    不要忘记在 crontab 文件中使用 \% 转义 %

    * * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
    

    【讨论】:

    • 如果有人像我一样想知道: %N 提供了当前的 nanos,但有些手册页缺少相关信息。对于那些只需要每个命令轻松“一些随机性”的人来说,这是一个非常聪明的解决方案。
    • 除了其他地方已经提到的警告外,这只有在你有 GNU date 时才有效(你可能在大多数 Linux 上这样做,但在 Busybox、标准 MacOS 或其他各种 BSD 派生的平台)。
    【解决方案6】:

    对于那些在这里用谷歌搜索的人:

    如果您使用的是 anacron(Ubuntu 台式机和笔记本电脑),那么您可以编辑

    /etc/anacrontab
    

    并添加

    RANDOM_DELAY=XX 
    

    其中 XX 是您希望延迟基本作业的分钟数。

    Anacron 与 cron 类似,但它不希望您的计算机 24x7 全天候运行(就像我们的笔记本电脑一样),并且会运行由于系统关闭而错过的脚本。

    【讨论】:

      【解决方案7】:

      at -f [file] [timespec]

      echo [command] | at [timespec]

      at [timespec] ... 和交互规范 喜欢script的录音。

      命令

      在运行时,文本在 stdin-f [file] 指定的文件中提供。

      时间规格

      这是[timespec] grammar。可以是这样的:

      • 24 小时时间为 4 位整数,例如0100, 2359, 1620
      • now + 10 minutes
      • 2071-05-31 - 5 hours 12 minutes UTC

      如果您明确指定时区,则 timespec 的 some versions 可能只允许 UTC 作为可选时区参数。

      示例

      cat script.sh | at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

      at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

      试试看...

      您可以通过预先添加 echo 并转义 |(管道)来测试 bash 解析。

      echo cat script.sh \| at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

      echo at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

      要查看计划的作业,请使用atq 和作业内容(环境变量、设置和命令/脚本)和at -c [jobid]

      注意

      系统是 cron 的一部分,交互式提示实际上捕获了 shell 的整个当前状态,因此您可以在不指定绝对路径的情况下运行命令。

      【讨论】:

        【解决方案8】:

        Cron 提供了一个 RANDOM_DELAY 变量。详情请见crontab(5)

        RANDOM_DELAY 变量允许将作业启动延迟随机数量 分钟,上限由变量指定。

        这在anacron 工作中很常见,但在crontab 中也很有用。

        如果您有一些运行良好的作业,您可能需要小心这一点 (分钟)粒度和其他粗粒度。

        【讨论】:

        • 我很想使用 RANDOM_DELAY 变量,但在 Ubuntu 14.04.4 LTS 上的 crontab(5) 手册页中找不到任何提示。
        • 这很不幸。我想知道那里是否不支持。我看到它记录在 Centos 7 和 Arch Linux 的联机帮助页中。
        • 这似乎是正确的答案,但你能举个例子吗?
        • 请注意RANDOM_DELAY 只建立一次,并在守护进程的整个运行时保持不变。
        • RANDOM_DELAY 标志是 cronie-crond 的功能,而 Ubuntu 似乎正在运行缺少此标志的 vixie-cron
        【解决方案9】:

        所以我使用以下命令在凌晨 1 点到 330 点之间运行命令

        0 1 * * * perl -le 'sleep rand 9000' && *command goes here*
        

        这一直在照顾我对我的随机需求。那是 9000 秒 == 150 分钟 == 2.5 小时

        【讨论】:

        • ::MindBLOWN:: 另一个使用一点 perl 的不起眼的地方。
        • 这绝对是最干净的答案
        • 这有点低效,因为你要创建很多进程。
        【解决方案10】:

        是的,是的,这个问题已经有一年多了,但也许我可以添加一些有用的东西:

        如何在每天上午 9 点到晚上 11 点之间以 20 次随机偏移量 cron 某项内容?这在 cron 中有点棘手,因为您将 14 小时除以 20 执行时间。我不太喜欢其他答案,因为它们需要为您的 php 脚本编写一个 bash 包装脚本。

        但是,如果您允许我在上午 8:30 到晚上 11:09 之间将时间和频率限制放宽到 13 次,这可能会奏效,并且所有这些都在您的 crontab 范围内:

        30 8-21/* * * * sleep ${RANDOM:0:2}m ; /path/to/script.php
        

        ${RANDOM:3:2} 使用了上面其他人提到的 bash 的 $RANDOM,但是添加了 bash 数组切片。由于 bash 变量是无类型的,伪随机有符号 16 位数字被截断为其 5 个十进制数字的前 2 个,为您提供一个简洁的单行代码,用于将您的 cronjob 延迟 10 到 99 分钟(尽管分布偏向于10 到 32)。

        以下内容也可能对您有用,但由于某种原因,我发现它确实“不那么随机”(也许本福德定律是通过调制伪随机数触发的。嘿,我不知道,我数学不及格...... . 归咎于 bash!):

        30 8-21/* * * * sleep $[RANDOM\%90]m ; /path/to/script.php
        

        您需要将模数呈现为上面的 '\%',因为 cron(至少 Linux 'vixie-cron')在遇到未转义的 '%' 时会终止该行。

        也许您可以通过添加另一个 7 小时范围的另一行来获得剩余的 7 个脚本执行。或者放宽在凌晨 3 点到晚上 11 点之间跑步的限制。

        【讨论】:

        • 我喜欢迟到的答案。但是如果你想生成一个均匀分布在 10 到 99 范围内的随机整数,而 RANDOM 的输出是 0 到 32,767,那你为什么不直接做$[(RANDOM/368)+10]呢?
        • @jsdalton:模运算符不是更好吗? $((RANDOM % 90 + 10)) 测试:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
        • 在许多系统上,cron 默认情况下不使用 bash,因此最好避免使用 bashism $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m
        • 在使用$RANDOM之前确保crontab使用bash如果你有vixie-cron(在Ubuntu上似乎是我的情况),那么您可以将SHELL=/bin/bash 添加到顶部。这里还有其他 cron 版本的替代方案:superuser.com/a/264541/260350
        • 当我使用上面的第一个建议时,我得到crontab: errors in crontab file, can't install. Do you want to retry the same edit? please help
        【解决方案11】:

        我的第一个想法是创建一个 cron 作业,启动 20 个随机安排的作业。 at 实用程序 (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) 用于在指定时间执行命令。

        【讨论】:

        【解决方案12】:

        如果我明白你在寻找什么,你需要做一些有点混乱的事情,比如让一个 cron 作业运行一个随机化运行时间的 bash 脚本......这样的事情:

        crontab:

        0 9 * * * /path/to/bashscript
        

        并在 /path/to/bashscript:

        #!/bin/bash
        
        maxdelay=$((14*60))  # 14 hours from 9am to 11pm, converted to minutes
        for ((i=1; i<=20; i++)); do
            delay=$(($RANDOM%maxdelay)) # pick an independent random delay for each of the 20 runs
            (sleep $((delay*60)); /path/to/phpscript.php) & # background a subshell to wait, then run the php script
        done
        

        一些注意事项:这种方法有点浪费资源,因为它在上午 9 点启动 20 个后台进程,每个进程等待随机数分钟(最长 14 小时,即晚上 11 点),然后启动php 脚本并退出。此外,由于它使用随机的分钟数(不是秒数),因此开始时间并不像它们可能的那样随机。但是 $RANDOM 只上升到 32,767,并且在上午 9 点到晚上 11 点之间有 50,400 秒,随机化秒数也会稍微复杂一些。最后,由于开始时间是随机的并且彼此独立,因此有可能(但不太可能)脚本的两个或多个实例同时启动。

        【讨论】:

        • 您可以通过删除美元符号并将双括号向左移动(例如((maxdelay = 14 * 60))((delay = $RANDOM % maxdelay)))来使算术分配更具可读性。 sleep 参数仍然需要是您拥有它的方式(尽管您可以添加空格,如果需要)。
        • 这对我也有用。我的自定义 bash 脚本如下所示sleep $[ ( $RANDOM % 60 ) + 1 ]s &amp;&amp; some_script.sh
        • 我错过了什么还是最大延迟应该设置为 maxdelay=$((14*60/20))
        • @jenishSakhiya 20 次运行中的每一次的随机延迟都是绝对的(嗯,从上午 9 点开始),与其他运行无关。也就是说,如果其中一个随机延迟出现在 13 小时,这意味着它将在晚上 10 点(上午 9 点后的 13 小时)运行,而不是在任何其他运行后的 13 小时。
        猜你喜欢
        • 2014-12-22
        • 1970-01-01
        • 1970-01-01
        • 2013-02-05
        • 2015-06-23
        • 2014-01-02
        • 2011-09-02
        • 1970-01-01
        • 2019-05-23
        相关资源
        最近更新 更多