119 votes

Travaux Cron et heures aléatoires, dans des heures données

Je dois pouvoir exécuter un script 20 fois par jour à des heures complètement aléatoires. Je veux également qu'il ne s'exécute qu'entre 9 h et 23 h.

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

2 votes

La question n'est pas très bien posée. En fin de compte, vous voulez distribuer 20 points sur l'axe du temps entre 9 heures et 11 heures. Mais existe-t-il des contraintes sur la différence de temps minimale ? Ne rien faire entre 9h et 10h30 est-il acceptable ? La seule façon d'y parvenir de manière acceptable semble être l'idée de Klaus : sélectionnez vos 20 heures à 09:00, ce qui vous permet de respecter toutes les contraintes que vous pourriez avoir, puis programmez les choses avec "à".

160voto

al-x Points 1645

Oui, oui, la question date de plus d'un an, mais je peux peut-être ajouter quelque chose d'utile :

Comment programmer quelque chose à un décalage aléatoire 20 fois par jour entre 9 h et 23 h ? C'est un peu délicat avec cron, car il faut diviser 14 heures par 20 exécutions. Je n'aime pas beaucoup les autres réponses car elles nécessitent d'écrire un wrapper bash script pour votre script php.

Toutefois, si vous me permettez d'assouplir la restriction de temps et de fréquence à 13 fois entre 8 h 30 et 23 h 09, cela pourrait faire l'affaire, tout en restant 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 de tableau de bash. Comme les variables bash ne sont pas typées, le nombre pseudo-aléatoire signé de 16 bits est tronqué aux 2 premiers de ses 5 chiffres décimaux, ce qui vous donne une phrase succincte pour retarder votre cronjob de 10 à 99 minutes (bien que la distribution penche vers 10 à 32).

La méthode suivante pourrait également vous convenir, mais je l'ai trouvée "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 été recalé en maths... C'est la faute de Bash !) :

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

Vous devez rendre le module comme '\%' ci-dessus parce que cron (du moins, le 'vixie-cron' de Linux) termine la ligne lorsqu'il rencontre un '%' non encodé.

Vous pourriez peut-être obtenir les 7 autres script exécutions en ajoutant une autre ligne avec une autre plage de 7 heures. Ou relâchez votre restriction d'exécution entre 3h du matin et 11h du soir.

4 votes

J'aime la réponse tardive. Mais si vous essayez de générer un entier aléatoire distribué uniformément dans la plage de 10 à 99, et que la sortie de RANDOM est de 0 à 32 767, pourquoi ne pas simplement faire $[(RANDOM/368)+10] ?

3 votes

@jsdalton : L'opérateur modulo ne serait-il pas mieux ? $((RANDOM % 90 + 10)) Test : for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c

6 votes

Sur de nombreux systèmes, cron n'utilise pas bash par défaut, il est donc préférable d'éviter le bashisme. $RANDOM : sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m .

78voto

Dave Points 781

J'utilise donc ce qui suit pour exécuter une commande entre 1 heure et 330 heures du matin.

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

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

9 votes

::MindBLOWN: : un autre endroit obscur pour utiliser un peu de perl.

1 votes

C'est certainement la réponse la plus propre

0 votes

Cette méthode est cependant inefficace, car elle crée un grand nombre de processus.

44voto

Gordon Davisson Points 22534

Si je comprends ce que vous recherchez, vous devrez faire quelque chose d'un peu désordonné, comme avoir une tâche cron qui exécute un bash script qui randomise les temps d'exécution.... Quelque chose comme ça :

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 remarques : cette approche est un peu gaspilleuse de ressources, car elle déclenche 20 processus d'arrière-plan à 9 heures du matin, chacun d'entre eux attendant pendant un nombre aléatoire de minutes (jusqu'à 14 heures, c'est-à-dire 23 heures), puis lance le script php script et sort. De plus, comme elle 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 va 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émarrage 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.

2 votes

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 ex. ((maxdelay = 14 * 60)) o ((delay = $RANDOM % maxdelay)) ). Le site sleep L'argument doit toujours être tel que vous l'avez (mais vous pouvez ajouter des espaces, si vous le souhaitez).

1 votes

Cela a aussi fonctionné pour moi. Mon bash script personnalisé ressemble à ce qui suit sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh

0 votes

J'ai raté quelque chose ou le délai maximum devrait être fixé à maxdelay=$((14*60/20))

26voto

Micah Elliott Points 11

Cron offre un RANDOM_DELAY variable. Voir crontab(5) pour les détails.

La variable RANDOM_DELAY permet de retarder le démarrage des tâches d'un nombre aléatoire de minutes. minutes, la limite supérieure étant spécifiée par la variable.

Cela se produit souvent dans anacron mais peut également être utile dans un crontab .

Vous devrez peut-être faire attention à cela si vous avez des tâches qui s'exécutent à une granularité fine (minute). (minute) et d'autres qui sont grossières.

0 votes

J'aimerais utiliser la variable RANDOM_DELAY, mais je ne trouve aucune indication dans la page de manuel de crontab(5) sur Ubuntu 14.04.4 LTS.

0 votes

C'est malheureux. Je me demande s'il n'est pas pris en charge là-bas. Je le vois documenté dans cette page de manuel sur Centos 7 et Arch Linux.

9 votes

Cela semble être la bonne réponse mais pouvez-vous donner un exemple ?

8voto

131 Points 645

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

Le préfixe 1 permet de forcer l'interprétation NON en 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

2 votes

Si quelqu'un se demande, comme moi : %N fournit les nanos actuels, mais certaines pages de manuel manquent d'informations à ce sujet. Il s'agit d'une solution très intelligente pour les personnes qui ont juste besoin d'un "peu d'aléatoire" facilement par commande.

0 votes

En dehors des avertissements déjà couverts 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 plateformes dérivées de BSD).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X