Problème avec $ RANDOM dans crontab


9

J'ai un étrange problème avec $ RANDOM dans cron. Je souhaite exécuter une commande un nombre aléatoire de minutes après le déclenchement du cronjob.

Cet exemple fonctionne directement dans le terminal et retarde la commande jusqu'à 30 secondes (remplacez la commande par ce que vous voulez, c'est en fait un écho à / dev / ttyUSB0):

sleep `expr $RANDOM \% 30` ; command

Si la même ligne est placée dans crontab, la commande se déclenche toujours immédiatement sans délai:

* * * * * sleep `expr $RANDOM \% 30` ; command

Si j'utilise une expression sans $ RANDOM, cela fonctionne très bien - cela fait un délai de 15 secondes:

* * * * * sleep `expr 10 + 5` ; command

En d'autres termes, il semble que $ RANDOM ne fonctionne pas dans un cron.

Mais ce n'est pas simplement parce que $ RANDOM lui-même est évalué à zéro, car cela devrait donner un délai de 10:

* * * * * sleep `expr $RANDOM \% 30 + 10` ; command

J'ai également essayé avec && instread de; mais cela n'aide pas. En fait, alors la commande ne se déclenche pas du tout!

Je pourrais bien sûr placer le retard dans un script qui est ensuite appelé depuis crontab, mais cela n'explique pas mon problème et ne me fait pas apprendre :-)

C'est Debian Lenny si cela fait une différence.

Réponses:


17

cronutilise le /bin/shshell pour exécuter des tâches. Dans certaines distributions, il s'agit d'un lien symbolique vers dash. Aucun d'eux ne prend en charge la $RANDOMvariable, qui est une bashextension spécifique.

  • Avec vixie-cron, vous pouvez mettre une ligne SHELL=/bin/bashen haut de votre crontab.

  • Sinon, vous devrez régler avec bash -c 'echo $RANDOM'ou perl -e 'print int(rand(65535))'.

    (Dans l'exemple ci-dessus, 65535 est le nombre maximum à renvoyer. Vous pouvez également appliquer d'autres mathématiques dans le script.)

  • Dans un système correctement configuré, vous auriez été informé de cela par cronlui-même - il envoie toujours la sortie du travail, y compris les messages d'erreur, par e-mail. Installez un MTA léger.


De plus, en bash, $(( ))est préférable à `expr`.


La dernière fois que j'ai vérifié, /bin/shn'était pas un shell réel, simplement un lien symbolique vers le shell préféré du sysadmin (généralement bash ou dash) sur Debian.
Hello71

1
@ Hello71: C'est ce que j'ai dit dans le post. Néanmoins, il est habituel que le logiciel système invoque /bin/sh(et s'attend à ce qu'il soit compatible avec le shell Bourne). Un exemple est la system()fonction dans la glibc. Par conséquent, /bin/shpointe généralement vers le shell compatible Bourne le plus rapide ; et l'administrateur système est censé définir sa préférence dans la ligne appropriée de / etc / passwd, et non pas appliquer cette préférence à l'échelle du système
user1686

@ Hello71: ... d'accord, surtout ce que j'ai dit dans le post. (Je connais la plupart des autres distributions shvers bash, mais cela ne semblait pas pertinent.)
user1686

Vous avez raison, /bin/shpointe pour se précipiter. Jusqu'à présent, je n'ai jamais entendu parler de dash. Je l'ai recherché et c'est une variante légère de bash. De plus, je ne savais pas que cron fonctionnait dans un environnement "paralysé", mais cela explique divers autres problèmes que j'ai eu par le passé. En fait, j'ai commencé à utiliser, $(())mais comme cela ne fonctionnait pas, j'ai essayé toutes sortes de variantes et je me suis retrouvé avec expr- ce qui bien sûr ne fonctionnait pas non plus. Mais c'est là que j'ai fini :-) Est-il possible d'exécuter un shell bash normal sans les limitations d'utilisation bash -c 'xxxx'? Au fait, n'est-il pas possible de mettre des sauts de ligne dans les commentaires?
marlar

@marlar: 1) dashest un shell. Ce n'est pas plus ou moins normal que bash. Ce n'est pas une variante non plus. 2) Voir les points # 1 et # 2 dans la réponse.
user1686

2

crons'exécute généralement avec un environnement moins "complet", ce qui signifie que vous n'avez tout simplement pas à disposition plusieurs des mêmes variables d'environnement. Apparemment, $RANDOMc'est l'un d'entre eux, et en fait, votre sleepcommande échoue simplement avec une erreur en raison de la variable non définie - c'est pourquoi votre commande n'a pas pu s'exécuter du tout lorsque vous êtes passé à la &&place de ;. (Eh bien, en fait, $RANDOMc'est une fonction Bash, mais cronne fonctionne pas dans un environnement Bash complet, qui n'a évidemment pas cette fonction.)

Pour accomplir cette tâche, vous devrez utiliser un script Bash distinct, comme vous l'avez dit. Alternativement, vous pourriez être en mesure de trouver un moyen d'utiliser cat /dev/urandomdirectement dans la croncommande, mais il serait probablement plus facile de simplement déplacer ce que vous avez actuellement vers un script Bash séparé.


1
Ce n'est pas joli, mais j'ai trouvé cette solution qui est analogue à votre suggestion: sleep $ (expr od -An -N1 -i /dev/urandom\% 30); commande
marlar

1
$RANDOMne fait pas partie d'un environnement "complet". Cela n'a rien à voir avec les variables d'environnement définies au démarrage d'un processus. Il s'agit d'une variable spéciale créée "à la volée" dans bash. Sa nouvelle valeur est toujours générée chaque fois que la variable est lue. --- cronpar défaut /bin/sh, les systèmes sur lesquels il /bin/shn'est pas lié bash $RANDOMne fonctionneront pas par défaut.
pabouk
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.