Tâches Cron et horaires aléatoires, dans des heures données

100

J'ai besoin de la capacité d'exécuter un script PHP 20 fois par jour à des moments complètement aléatoires. Je veux également qu'il ne fonctionne qu'entre 9h et 23h.

Je suis familier avec la création de tâches cron sous Linux.

flotter
la source
1
La question n'est pas très bien posée. Au final, vous souhaitez répartir 20 points sur l'axe des temps entre 9h et 11h. Mais y a-t-il des contraintes sur le décalage horaire minimum? Ne rien faire entre 9h et 10h30 est acceptable? La seule façon de faire cela semble acceptable dans l'idée de Klaus: sélectionnez vos 20 fois à 09h00, ce qui vous permet de remplir toutes les contraintes que vous pourriez avoir, puis planifiez les choses avec "at".
David Tonhofer

Réponses:

38

Si je comprends ce que vous cherchez, vous devrez faire quelque chose d'un peu compliqué, comme avoir un travail cron qui exécute un script bash qui randomise les temps d'exécution ... Quelque chose comme ceci:

crontab:

0 9 * * * /path/to/bashscript

et dans / 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

Quelques notes: cette approche est un peu un gaspillage de ressources, car elle déclenche 20 processus d'arrière-plan à 9h, chacun attend pendant un nombre aléatoire de minutes (jusqu'à 14 heures, soit 23h), puis lance le script php et sorties. De plus, comme il utilise un nombre aléatoire de minutes (et non de secondes), les heures de début ne sont pas aussi aléatoires qu'elles pourraient l'être. Mais $ RANDOM ne monte que jusqu'à 32 767, et il y a 50 400 secondes entre 9h et 23h, ce serait un peu plus compliqué de randomiser les secondes également. Enfin, puisque les heures de début sont aléatoires et indépendantes les unes des autres, il est possible (mais peu probable) que deux ou plusieurs instances du script soient lancées simultanément.

Gordon Davisson
la source
2
Vous pouvez rendre les affectations arithmétiques plus lisibles en supprimant le signe dollar et en déplaçant les doubles parenthèses vers la gauche (par exemple ((maxdelay = 14 * 60))ou ((delay = $RANDOM % maxdelay))). L' sleepargument doit toujours être tel que vous l'avez (bien que vous puissiez ajouter des espaces, si vous le souhaitez).
Suspendu jusqu'à nouvel ordre.
Cela a fonctionné pour moi aussi. Mon script de bash personnalisé ressemble à cisleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada
Suis-je en train de manquer quelque chose ou le délai maximum doit être réglé sur maxdelay = $ ((14 *
60/20
@jenishSakhiya Les retards aléatoires pour chacune des 20 courses sont absolus (enfin, à partir de 9 heures du matin), pas par rapport à une autre des courses. Autrement dit, si l'un des retards aléatoires atteint 13 heures, cela signifie qu'il fonctionnera à 22 heures (13 heures après 9 heures), et non 13 heures après l'une des autres exécutions.
Gordon Davisson
138

Ouais, ouais, la question a plus d'un an, mais je peux peut-être ajouter quelque chose d'utile:

Comment cron quelque chose avec un décalage aléatoire 20 fois par jour entre 9h et 23h? C'est un peu délicat dans cron, car vous divisez 14 heures par 20 temps d'exécution. Je n'aime pas beaucoup les autres réponses car elles nécessitent l'écriture d'un script wrapper bash pour votre script php.

Cependant, si vous me permettez la liberté d'assouplir la restriction de synchronisation et de fréquence à 13 fois entre 8h30 et 23h09, cela pourrait faire l'affaire, et le tout dans les limites de votre crontab:

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

$ {RANDOM: 3: 2} utilise le $ RANDOM de bash que d'autres personnes ont mentionné ci-dessus, mais ajoute le découpage du tableau bash. Étant donné que les variables bash ne sont pas typées, le nombre 16 bits signé pseudo-aléatoire est tronqué aux 2 premiers de ses 5 chiffres décimaux, vous donnant une ligne succincte pour retarder votre travail cron entre 10 et 99 minutes (bien que la distribution soit biaisée vers 10 à 32).

Ce qui suit pourrait également fonctionner pour vous, mais j'ai trouvé que c'était "moins aléatoire" pour une raison quelconque (peut-être que la loi de Benford est déclenchée par la modulation de nombres pseudo-aléatoires. Hé, je ne sais pas, j'ai raté les mathématiques ... sur bash!):

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

Vous devez rendre le module comme '\%' ci-dessus car cron (enfin, au moins Linux 'vixie-cron') termine la ligne quand il rencontre un '%' sans échappement.

Peut-être que vous pourriez obtenir les 7 autres exécutions de script en ajoutant une autre ligne avec une autre plage de 7 heures. Ou relâchez votre restriction pour courir entre 3 h et 23 h.

al-x
la source
4
J'aime la réponse tardive. Mais si vous essayez de générer un entier aléatoire uniformément réparti dans la plage de 10 à 99, et que la sortie de RANDOM est de 0 à 32 767, pourquoi ne le feriez-vous pas $[(RANDOM/368)+10]?
jsdalton
3
@jsdalton: L'opérateur modulo ne serait-il pas meilleur? $((RANDOM % 90 + 10))Test:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon
5
On Cron de nombreux systèmes ne pas utiliser bash par défaut il pourrait être préférable d'éviter le bash $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
pabouk
9
Assurez-vous qu'il crontabutilise bashavant de l'utiliser $RANDOM. Si vous avez vixie-cron(semble être mon cas sur Ubuntu), vous pouvez ajouter SHELL=/bin/bashen haut. Il y a plus d'alternatives pour d'autres versions de cron ici: superuser.com/a/264541/260350
DaAwesomeP
1
Lorsque j'utilise la première suggestion ci-dessus, je reçois de l' crontab: errors in crontab file, can't install. Do you want to retry the same edit?aide s'il vous plaît
Seano
72

J'utilise donc ce qui suit pour exécuter une commande entre 1h00 et 330h00

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

Cela a pris soin de mes besoins aléatoires pour moi. Cela représente 9000 secondes == 150 minutes == 2,5 heures

Dave
la source
8
:: MindBLOWN :: un autre endroit obscur pour utiliser un peu de perl.
Mark Carpenter Jr
C'est certainement la réponse la plus
claire
C'est un peu inefficace, car vous créez de nombreux processus.
kahveciderin
21

Cron propose une RANDOM_DELAYvariable. Voir crontab(5)pour plus de détails.

La variable RANDOM_DELAY permet de retarder le démarrage des travaux par une quantité aléatoire de minutes avec une limite supérieure spécifiée par la variable.

Cela se voit couramment dans les anacronemplois, mais peut également être utile dans un fichier crontab.

Vous devrez peut-être faire attention à cela si vous avez des travaux qui s'exécutent avec une granularité fine (minute) et d'autres qui sont grossiers.

Micah Elliott
la source
J'adorerais utiliser la variable RANDOM_DELAY, mais je ne trouve aucun indice dans la page de manuel de crontab (5) sur Ubuntu 14.04.4 LTS.
Exocom
C'est malheureux. Je me demande si ce n'est pas pris en charge ici. Je le vois documenté dans cette page de manuel sur Centos 7 et Arch Linux.
Micah Elliott
9
cela semble être la bonne réponse, mais pouvez-vous donner un exemple?
chovy
14
Veuillez noter qu'il RANDOM_DELAYest établi une fois et reste constant pendant tout le temps d'exécution du démon.
Maciej Swic
5
Le RANDOM_DELAYdrapeau est une caractéristique de cronie-crond alors qu'Ubuntu semble fonctionner, vixie-cronce qui n'a pas cet indicateur.
kravietz
7

Ma première pensée serait de créer une tâche cron en lançant 20 tâches planifiées au hasard. L' atutilitaire (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) est utilisé pour exécuter des commandes à un moment spécifié.

Klaus
la source
Un exemple d'utilisation de at est ici: stackoverflow.com/a/6136145/803174
Kangur
6

J'ai fini par utiliser sleep $(( 1$(date +%N) % 60 )) ; dostuffs(compatible avec bash & sh)

Le préfixe 1 est de forcer l'interprétation NON base 8 de la date +% N (par exemple 00551454)

N'oubliez pas d'échapper% en utilisant \% dans un fichier crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
la source
2
Si quelqu'un se demande, comme moi:% N fournit les nanos actuels, mais certaines pages man manquent d'informations à ce sujet. C'est une solution très intelligente pour les personnes qui ont juste besoin de "quelques aléas" facilement par commande.
Thorsten Schöning
Outre les mises en garde déjà couvertes ailleurs, cela ne fonctionnera que si vous avez GNU date(ce que vous faites probablement sur la plupart des Linux, mais pas sur Busybox, MacOS standard ou diverses autres plates-formes dérivées de BSD).
tripleee
4

La solution d'al-x ne fonctionne pas pour moi puisque les commandes crontab ne sont pas exécutées dans bash mais dans sh je suppose. Ce qui fonctionne, c'est:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Wilbert
la source
J'ai tout essayé et cela n'a toujours pas fonctionné pour moi. Vous postez expliqué pourquoi, merci!
marlar
$[ ... ]est une syntaxe déconseillée depuis waaaay back; pour tout ce qui date de ce millénaire, vous préféreriez $((RANDOM\%90))mquelle syntaxe est compatible POSIX (mais bien sûr, RANDOMc'est toujours uniquement Bash).
tripleee
1

at -f [file] [timespec]

ou

echo [command] | at [timespec]

ou

at [timespec]... et des spécifications interactives comme scriptl'enregistrement de.

Commander

At exécute le texte fourni sur stdin ou dans le fichier spécifié par -f [file].

Timespec

Voici la [timespec] grammaire . Cela peut être quelque chose comme:

  • 24 heures comme int 4 chiffres, par exemple 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Si vous spécifiez explicitement le fuseau horaire, certaines versions de timespec peuvent n'autoriser UTCque l'argument de fuseau horaire facultatif.

Exemple

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

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

Essaye le...

Vous pouvez tester l'analyse bash en pré-en attente echoet en échappant le |(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

Pour voir les travaux planifiés, l'utilisation atqet le contenu des travaux (variables d'environnement, configuration et commande / script) avec at -c [jobid].

Remarque

Le système fait partie de cron et l'invite interactive capture en fait tout l'état actuel de votre shell, vous pouvez donc exécuter des commandes sans spécifier de chemins absolus.

Mcint
la source
0

Pour ceux qui ont parcouru le chemin ici:

Si vous utilisez anacron (bureau et ordinateur portable Ubuntu), vous pouvez modifier

/etc/anacrontab

et ajouter

RANDOM_DELAY=XX 

Où XX est le nombre de minutes que vous souhaitez retarder le travail de base.

Anacron est comme cron mais il ne s'attend pas à ce que votre ordinateur soit en mode 24x7 (comme nos ordinateurs portables) et exécutera les scripts qu'il a manqués parce que le système était en panne.

Ganesh Krishnan
la source
0

Vous pouvez essayer avec cet exemple d'utiliser des temps aléatoires avant d'exécuter la commande:

#!/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"
Houssin Boulla
la source
0

Qu'en est-il de la création d'un script qui réécrit la crontab tous les jours?

  1. Lire les crons actuels (A)
  2. Choisissez des moments aléatoires (B)
  3. Réécrire les crons précédents (A), ajouter de nouveaux crons aléatoires (B)
  4. Assurez-vous d'ajouter au cron pour exécuter ce script en premier lieu.
moelleux
la source
2
Ne contournez pas le système de réputation en publiant des commentaires comme réponses. Votre commentaire semble cependant assez bon pour être une réponse. Je recommande de supprimer " Je n'ai pas de représentant pour ajouter un commentaire, mais ".
Ted Lyngmo
1
Je viens de passer en revue cette réponse et j'ai raté la partie où vous posez une question en retour à la fin (travail bâclé de ma part). Ne posez pas de questions dans les réponses. Postez votre propre question pour les questions que vous avez. J'ai fait de votre demi-question quelque chose qui pourrait passer pour une réponse.
Ted Lyngmo
1
Je l'ai! THX. Je serai plus prudent la prochaine fois, aucune mauvaise intention n'était signifiée.
mellofellow le
1
Je suis sûr que vous n'aviez aucune mauvaise intention et que vous n'avez pas besoin d'être trop prudent. Vous avez présenté une solution possible - et vous avez un peu trébuché à la fin. Pas de soucis!
Ted Lyngmo le
0

Je me rends compte que c'est un fil plus ancien, mais je veux ajouter un élément lié à une valeur aléatoire que j'utilise beaucoup. Au lieu d'utiliser la variable $ RANDOM avec une plage fixe et limitée, je crée souvent des valeurs aléatoires de plage arbitraire dans le shell avec

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

afin que vous puissiez faire, par exemple,

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

et surmonter certaines des restrictions qui ont été discutées dans ce fil.

MLP
la source
1
Bienvenue à SO. Eh bien, vieux fil ou pas, cela m'a envoyé ~$info ddet je peux comprendre ce qui se passe sur le côté gauche de |, mais je ne peux pas distinguer le côté droit. Donc, pour moi et pour d'autres intéressés par overcoming some restrictionsla génération de valeur aléatoire, pourquoi ne pas prendre un moment pour expliquer le RHS et faire un argumentaire plus fort pour utiliser votre approche. La profondeur de l'explication rend les gens à l'aise avec le processus que vous suggérez et ses avantages. Merci.
Chris
Ah ok. od aka "octal dump" prend un fichier ou stdin et vide les données binaires sous une forme lisible par l'homme. Nous voulons que notre nombre soit affiché sous forme de décimal non signé (-t u4), et ne voulons pas d'index d'adresse (-A aucun). Le -N4 est redondant car nous ne prenons que 4 octets, mais ne fait pas de mal non plus. J'espère que cela l'explique ...
MLP