Cron 作业和随机时间,在给定的小时内

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

我很熟悉在 Linux 中创建 cron 作业。

131888 次浏览

如果我知道你在寻找什么,你需要做一些有点麻烦的事情,比如有一个 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秒的时间,因此随机化这些秒也会有点复杂。最后,由于开始时间是随机的并且彼此独立,所以脚本的两个或多个实例有可能(但不太可能)同时开始。

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

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

如何在上午9点到晚上11点之间随机偏移20次?这在 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位,给你一个简洁的一行程序,延迟您的错误工作在10到99分钟之间(虽然分布是偏向于10到32)。

下面的方法可能也适用于你,但是我发现由于某些原因,它确实“不那么随机”(也许本福特定律是通过调节伪随机数来触发的。嘿,我不知道,我数学不及格... 都怪 Bash!):

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

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

也许您可以通过添加另一行7小时范围的代码来执行剩下的7个脚本。或者放宽你的限制,在上午3点到晚上11点之间跑步。

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

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

那就是9000秒 = = 150分钟 = = 2.5小时

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

前缀1是强制 NON 基于8的日期 +% N 的解释(例如00551454)

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

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

一些 cron 实现提供了一个 RANDOM_DELAY变量。

RANDOM _ DELAY 变量允许延迟工作启动的随机数量 分钟,上限由变量指定。

详情见 crontab(5)

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

如果您有一些运行良好的作业,那么您可能需要小心使用它 (分钟)粒度和其他粗糙的。

at -f [file] [timespec]

或者

echo [command] | at [timespec]

或者

和交互式规范 比如 script的录音。

命令

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

时间规格

这里是 [timespec] 语法 。它可以类似于:

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

如果显式指定时区,timespec 的 一些版本可能只允许 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 的整个当前状态,因此您可以在不指定绝对路径的情况下运行命令。

对于那些在谷歌上搜索到这里的人来说:

如果你正在使用 anacron (Ubuntu 桌面和笔记本电脑) ,那么你可以编辑

/etc/anacrontab

然后加

RANDOM_DELAY=XX

其中 XX 是要延迟基本作业的分钟数。

Anacron 类似于 cron,但是它不希望你的电脑像我们的笔记本电脑一样24x7运行,并且会运行因为系统故障而错过的脚本。

Al-x 的解决方案对我来说不起作用,因为 crontab 命令不是在 bash 中执行的,而是在 sh 中执行的。有效的方法是:

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

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

#!/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"

如何创建一个每天重写 crontab 的脚本?

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

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

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)

并克服了这个线程中讨论的一些限制。

我也在寻找同样的问题,对我来说,最好的解决方案是在服务器端创建一个调度(通过编程语言来实现非常简单) ,用这些任务填充一个 db 表,其中包含两列: run _ time 和 status (new | Processing)。因此,我的 cron 每分钟运行一次,并找到需要完成的作业(status = new and running time < = now ())。 非常简单,而且有一个巨大的优点: 在这种情况下,我可以为它制作一个接口,看看会发生什么..。