Задания Cron и случайное время в течение заданных часов

101

Мне нужна возможность запускать PHP-скрипт 20 раз в день в совершенно произвольное время. Я также хочу, чтобы он работал только с 9 до 23 часов.

Я знаком с созданием рабочих мест cron в Linux.

плыть налево
источник
1
Вопрос не очень хорошо поставлен. В конечном итоге вы хотите распределить 20 точек по оси времени между 9 и 11 часами утра. Но есть ли ограничения на минимальную разницу во времени? Разве можно ничего не делать с 9 утра до 10:30? Единственный способ сделать это приемлемо, по мнению Клауса: выберите 20 раз в 09:00, что позволяет выполнить любые ограничения, которые могут у вас возникнуть, а затем запланировать дела с помощью «at».
Дэвид Тонхофер,

Ответы:

38

Если я понимаю, что вы ищете, вам нужно сделать что-то немного беспорядочное, например, создать задание cron, которое запускает сценарий bash, который рандомизирует время выполнения ... Примерно так:

crontab:

0 9 * * * /path/to/bashscript

и в / путь / к / 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

Несколько примечаний: этот подход немного расточителен, поскольку он запускает 20 фоновых процессов в 9 утра, каждый из которых ждет случайное количество минут (до 14 часов, т.е. 11 вечера), затем запускает скрипт php и выходы. Кроме того, поскольку он использует случайное количество минут (не секунд), время начала не такое уж случайное, как могло бы быть. Но $ RANDOM увеличивается только до 32 767, а между 9 утра и 11 вечера есть 50 400 секунд, было бы немного сложнее рандомизировать секунды. Наконец, поскольку время запуска случайное и не зависит друг от друга, возможно (но маловероятно), что два или более экземпляра скрипта будут запущены одновременно.

Гордон Дэвиссон
источник
2
Вы можете сделать арифметические присвоения более удобочитаемыми, убрав знак доллара и сдвинув двойные скобки влево (например, ((maxdelay = 14 * 60))или ((delay = $RANDOM % maxdelay))). sleepАргумент еще должен быть путь у вас есть (хотя вы можете добавить пробелы, если это необходимо).
Приостановлено до дальнейшего уведомления.
1
Это сработало и для меня. Мой пользовательский сценарий bash выглядит так, как sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
показано
Мне что-то не хватает, или максимальная задержка должна быть установлена ​​на maxdelay = $ ((14 *
60/20
@jenishSakhiya Случайные задержки для каждого из 20 прогонов абсолютны (ну, начиная с 9 утра), а не относительно другого из прогонов. То есть, если одна из случайных задержек составляет 13 часов, это означает, что она будет работать в 22:00 (13 часов после 9:00), а не через 13 часов после любого из других запусков.
Гордон Дэвиссон
139

Да, да, этому вопросу больше года, но, может быть, я могу добавить что-нибудь полезное:

Как выполнить cron с произвольным смещением 20 раз в день с 9 утра до 11 вечера? В cron это довольно сложно, потому что вы делите 14 часов на 20 времени выполнения. Мне не очень нравятся другие ответы, потому что они требуют написания сценария-оболочки bash для вашего php-сценария.

Однако, если вы позволите мне облегчить ограничение времени и частоты до 13 раз с 8:30 до 23:09, это может помочь, и все это в пределах вашего crontab:

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

$ {RANDOM: 3: 2} использует $ RANDOM из bash, о котором упоминалось выше, но добавляет нарезку массива bash. Поскольку переменные bash не типизированы, псевдослучайное подписанное 16-битное число усекается до первых 2 из 5 десятичных цифр, что дает вам краткую однострочную запись для задержки вашего 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
Во многих системах хрон не использует Баш по умолчанию , так что может быть лучше , чтобы избежать bashism $RANDOM: sleep $(( $(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
1
Когда я использую первое предложение выше, я получаю, crontab: errors in crontab file, can't install. Do you want to retry the same edit?пожалуйста, помощь
Сеано
72

Итак, я использую следующее для запуска команды между 01:00 и 330:00.

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

Это позаботилось о моих случайных потребностях. Это 9000 секунд == 150 минут == 2,5 часа

Дэйв
источник
8
:: MindBLOWN :: еще одно непонятное место, где можно использовать немного Perl.
Марк Карпентер-младший,
Это определенно самый чистый ответ
Энрико Детома
Это неэффективно, поскольку вы создаете много процессов.
kahveciderin
21

Cron предлагает RANDOM_DELAYпеременную. Подробнее crontab(5)см.

Переменная RANDOM_DELAY позволяет задерживать запуск задания на произвольное количество минут с верхним пределом, указанным переменной.

Это часто встречается на anacronрабочих местах, но также может быть полезно в crontab.

Вам может потребоваться быть осторожным с этим, если у вас есть некоторые задания, которые выполняются с мелкой (минутной) детализацией, а другие - с грубой.

Мика Эллиотт
источник
Я хотел бы использовать переменную RANDOM_DELAY, но не могу найти никаких подсказок на странице руководства crontab (5) в Ubuntu 14.04.4 LTS.
Exocom
Это неудачно. Интересно, а там не поддерживается. Я вижу это задокументировано на этой странице руководства по Centos 7 и Arch Linux.
Мика Эллиотт,
9
это кажется правильным ответом, но вы можете привести пример?
chovy
14
Обратите внимание, что RANDOM_DELAYон устанавливается один раз и остается постоянным в течение всего времени работы демона.
Maciej Swic
5
RANDOM_DELAYФлаг особенность cronie-crond в то время как Ubuntu , кажется, работает в vixie-cronкотором отсутствует этот флаг.
kravietz
7

Моя первая мысль заключалась в том, чтобы создать одно задание cron, запускающее 20 заданий, случайно запланированных для этого. atПолезности (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) используются для выполнения команд в заданное время.

Клаус
источник
Пример использования в здесь: stackoverflow.com/a/6136145/803174
Kangur
6

В итоге я использовал sleep $(( 1$(date +%N) % 60 )) ; dostuffs(совместим с bash & sh)

Префикс 1 означает, что дата не интерпретируется по основанию 8 +% N (например, 00551454).

Не забудьте экранировать%, используя \% в файле crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
источник
2
Если кому-то интересно, например, мне:% N предоставляет текущие наноразмеры, но на некоторых страницах руководства отсутствует информация по нему. Это очень умное решение для людей, которым просто нужна «некоторая случайность» для каждой команды.
Thorsten Schöning
Помимо предостережений, уже описанных в другом месте, это будет работать, только если у вас есть GNU date(что вы, вероятно, делаете на большинстве Linux, но не на Busybox, стандартной MacOS или различных других платформах, основанных на BSD).
тройняшек
4

Решение al-x не работает для меня, поскольку команды crontab выполняются не в bash, а в sh, я думаю. Что работает:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Уилберт
источник
Я перепробовал все, но у меня все равно не получилось. Ваш пост объяснил, почему, спасибо!
marlar
$[ ... ]является устаревшим синтаксисом с тех пор, как он вернулся; для чего-либо из этого тысячелетия вы бы предпочли $((RANDOM\%90))mPOSIX-совместимый синтаксис (но, конечно, RANDOMпо-прежнему только Bash).
тройняшек
1

at -f [file] [timespec]

или

echo [command] | at [timespec]

или

at [timespec]... и интерактивная спецификация, такая как scriptзапись.

Команда

При запуске текст предоставляется на стандартный ввод или в файл, указанный в -f [file].

Timespec

Вот [timespec] грамматика . Это может быть что-то вроде:

  • 24-часовое время , как 4-значного междунар, например 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Если вы явно указываете часовой пояс, некоторые версии спецификации времени могут допускать только UTCнеобязательный аргумент часового пояса.

пример

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

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

Попробуйте ...

Вы можете протестировать синтаксический анализ bash, предварительно отложив echoи экранировав |(pipe).

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, и интерактивное приглашение фактически фиксирует все текущее состояние вашей оболочки, поэтому вы можете запускать команды без указания абсолютных путей.

mcint
источник
0

Для тех, кто гуглил путь сюда:

Если вы используете Anacron (настольный компьютер и ноутбук Ubuntu), вы можете редактировать

/etc/anacrontab

и добавить

RANDOM_DELAY=XX 

Где XX - это количество минут, на которое вы хотите отложить базовое задание.

Anacron похож на cron, но он не ожидает, что ваш компьютер будет работать круглосуточно (как наши ноутбуки), и будет запускать сценарии, которые он пропустил из-за того, что система вышла из строя.

Ганеш Кришнан
источник
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
Понял! Спасибо. В следующий раз я буду поосторожнее, никаких злых умыслов не было.
mellofellow
1
Я уверен, что у вас не было злых умыслов, и вам не нужно быть слишком осторожным. Вы наметили возможное решение - и в конце немного споткнулись. Не беспокойся!
Тед Люнгмо,
0

Я понимаю, что это старый поток, но я хочу добавить одну вещь, связанную со случайными значениями, которую я часто использую. Вместо использования переменной $ 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)

и преодолеть некоторые ограничения, которые обсуждались в этой ветке.

MLP
источник
1
Добро пожаловать в SO. Что ж, старая ветка или нет, это отправило меня, ~$info ddи я могу понять, что происходит с левой стороны |, но не могу разобрать правую сторону. Итак, для меня и других, интересующихся overcoming some restrictionsгенерацией случайных значений, почему бы не уделить время объяснению RHS и сделать более убедительный аргумент в пользу использования вашего подхода. Глубина объяснения позволяет людям чувствовать себя комфортно как с процессом, который вы предлагаете, так и с его преимуществами. Спасибо.
Крис
Ах хорошо. od aka «восьмеричный дамп» принимает файл или стандартный ввод и выгружает двоичные данные в удобочитаемой форме. Мы хотим, чтобы наш номер отображался в виде десятичной дроби без знака (-t u4), и нам не нужен индекс адреса (-A none). -N4 является избыточным, поскольку мы берем только 4 байта, но это тоже не повредит. Надеюсь, это объясняет ...
MLP