指定时间内的Cron工作和随机时间


99

我需要能够每天完全随机地运行20次PHP脚本。我也希望它仅在上午9点至晚上11点之间运行。

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


1
这个问题提出得不是很好。最终,您想在上午9点到上午11点之间在时间轴上分配20个点。但是最小时差是否有限制?在9am到10:30 am之间什么都不做是可以接受的吗?做到这一点的唯一方法似乎是克劳斯的主意:在09:00选择20次,这使您可以满足可能遇到的任何限制,然后使用“ at”安排时间。
David Tonhofer,2013年

Answers:


37

如果我了解您要查找的内容,则需要做一些混乱的事情,例如执行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秒,随机分配秒也要复杂一点。最后,由于开始时间是随机的并且彼此独立,因此有可能(但不太可能)同时启动两个或更多脚本实例。


2
您可以通过以下操作使算术运算更具可读性:放下美元符号,然后将双括号移到左侧(例如((maxdelay = 14 * 60))((delay = $RANDOM % maxdelay)))。该sleep参数仍然必须是您拥有该参数的方式(尽管您可以根据需要添加空格)。
暂停,直到另行通知。

这也对我有用。我的自定义bash脚本如下所示 sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada

我错过了什么吗,或者最大延迟应设置为maxdelay = $(((14 *
60/20

@jenishSakhiya 20个运行中的每个运行的随机延迟都是绝对的(好,从上午9点开始),而不是相对于另一个运行。也就是说,如果其中一个随机延迟时间为13小时,则表示它将在晚上10点(上午9点后13小时)运行,而不是在其他任何间隔后13小时运行。
戈登·戴维森,

138

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

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

但是,如果您允许我在8:30 am到11:09 pm之间将时间和频率限制放宽到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)。

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

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

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

也许您可以通过添加另一个具有7小时范围的行来获得其余7个脚本执行。或放宽您的限制,以在凌晨3点至晚上11点之间运行。


4
我喜欢最新的答案。但是,如果您尝试生成在10到99之间均匀分布的随机整数,并且RANDOM的输出是0到32,767,那么为什么不这样做$[(RANDOM/368)+10]呢?
jsdalton

3
@jsdalton:模运算符会更好吗?$((RANDOM % 90 + 10))测试:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon

5
在许多系统上的cron默认不使用bash,因此可以更好地避免bashism $RANDOMsleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m
pabouk

9
crontab使用bash前请确保正在使用$RANDOM如果有vixie-cron(似乎是我在Ubuntu上的情况),则可以添加SHELL=/bin/bash到顶部。这里还有其他cron版本的替代方案:superuser.com/a/264541/260350
DaAwesomeP 2015年

1
当我使用上面的第一个建议时,我会得到crontab: errors in crontab file, can't install. Do you want to retry the same edit?帮助
-Seano

71

所以我正在使用以下命令在1AM和330AM之间运行命令

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

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


8
:: MindBLOWN ::另一个晦涩的地方,需要使用一点perl。
马克·卡彭特(Marc Carpenter Jr)

这绝对是最干净的答案
Enrico Detoma

21

克龙提供了一个RANDOM_DELAY变量。有关crontab(5)详细信息,请参见。

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

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

如果您有一些作业以精细(分钟)的粒度运行,而另一些则是粗糙的,那么您可能需要对此小心。


我很想使用RANDOM_DELAY变量,但是在Ubuntu 14.04.4 LTS上的crontab(5)的联机帮助页中找不到任何提示。
Exocom

那真不幸。我想知道那里是否不支持它。我在Centos 7和Arch Linux的联机帮助页中看到了该文档。
米卡·艾略特

9
这似乎是正确的答案,但您能举个例子吗?
chovy

14
请注意,该过程RANDOM_DELAY仅建立一次,并且在整个守护程序运行期间保持不变。
Maciej Swic '17

5
RANDOM_DELAY标志是cronie-crond的功能,而Ubuntu似乎正在运行vixie-cron,缺少此标志。
kravietz


6

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

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

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

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

2
如果有人像我一样感到疑惑:%N提供了当前的nanos,但是某些手册页缺少有关它的信息。对于只需要每个命令轻松地“随机性”的人来说,这是一个非常聪明的解决方案。
ThorstenSchöning16年

除了已经在其他地方讨论过的警告之外,这仅在拥有GNU的情况下才有效date(您可能在大多数Linux上都可以这样做,但在Busybox,标准MacOS或其他各种BSD衍生平台上却没有)。
tripleee

4

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

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

我尝试了一切,但仍然对我不起作用。您的帖子解释了原因,谢谢!
Marlar

$[ ... ]从waaaay返回后已弃用的语法;对于这个千年以来的任何事情,您都希望使用$((RANDOM\%90))m与POSIX兼容的语法(但是当然RANDOM仍然仅是Bash)。
tripleee

1

at -f [file] [timespec]

要么

echo [command] | at [timespec]

要么

at [timespec]...以及诸如script的录音之类的交互式规范。

命令

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

时间规格

这是[timespec] 语法。可能是这样的:

  • 24小时时间为4位INT,例如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的整个当前状态,因此您可以在不指定绝对路径的情况下运行命令。


0

对于那些在这里搜索过的人:

如果您正在使用anacron(Ubuntu台式机和笔记本电脑),则可以进行编辑

/etc/anacrontab

并添加

RANDOM_DELAY=XX 

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

Anacron就像cron一样,但是它不希望您的计算机运行在24x7上(例如我们的笔记本电脑),并且会运行由于系统关闭而丢失的脚本。


0

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

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

0

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

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

2
不要通过发布评论作为答案来规避信誉系统。但是,您的评论看起来确实足够好,可以作为答案。我建议删除“ 我没有代表要添加评论,但是 ”。
特德·林格莫

1
我只是查看了此答案,却错过了最后问您一个问题的部分(我的工作很草率)。不要问答案中的问题。发表您自己的问题。我把您的半问题变成可以通过答案的问题。
特德·林格莫

1
得到它了!谢谢。下次我会更加小心,没有恶意。
6

1
我确定您没有恶意,也不必过于小心。您概述了一个可能的解决方案-并在最后无意中发现了一点。别担心!
特德·林格莫

0

我意识到这是一个较旧的线程,但是我想添加一个我经常使用的与随机值相关的东西。而不是使用固定范围和有限范围的$ 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)

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


1
欢迎来到SO。好的,无论是否使用旧线程,这使~$info dd我无法正常工作,我可以了解左侧的情况|,但无法确定右侧。因此,对于我和其他对overcoming some restrictions随机值生成感兴趣的人,为什么不花一点时间来解释RHS,并为使用您的方法做一个更强的建议。深入的解释都使人们对您建议的过程及其好处感到满意。谢谢。
克里斯

喔好吧。od也称为“八进制转储”,它获取文件或stdin并以人类可读的形式转储二进制数据。我们希望我们的数字显示为无符号十进制(-t u4),并且不希望地址索引(-A无)。-N4是多余的,因为我们仅占用4个字节,但也不会受到损害。我希望这能解释它……
MLP
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.