Problem mit $ RANDOM in crontab

9

Ich habe ein seltsames Problem mit $ RANDOM in cron. Ich möchte einen Befehl eine zufällige Anzahl von Minuten nach dem Auslösen des Cronjobs ausführen.

Dieses Beispiel funktioniert direkt im Terminal und verzögert den Befehl um bis zu 30 Sekunden (ersetzen Sie den Befehl durch einen beliebigen Befehl, es ist tatsächlich ein Echo an / dev / ttyUSB0):

sleep `expr $RANDOM \% 30` ; command

Wenn dieselbe Zeile in crontab platziert ist, wird der Befehl immer sofort und ohne Verzögerung ausgelöst:

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

Wenn ich einen Ausdruck ohne $ RANDOM verwende, funktioniert er einwandfrei - dies führt zu einer Verzögerung von 15 Sekunden:

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

Mit anderen Worten, es scheint, als ob $ RANDOM in einem Cron nicht funktioniert.

Dies liegt jedoch nicht einfach daran, dass $ RANDOM selbst zu Null ausgewertet wird, da dies dann eine Verzögerung von 10 ergeben sollte:

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

Ich habe es auch mit && instread of versucht; aber das hilft nicht. Tatsächlich wird der Befehl dann überhaupt nicht ausgelöst!

Ich könnte die Verzögerung natürlich in ein Skript einfügen, das dann von crontab aufgerufen wird, aber das erklärt mein Problem nicht und bringt mich nicht zum Lernen :-)

Es ist Debian Lenny, wenn das einen Unterschied macht.

Marlar
quelle

Antworten:

17

cronverwendet die /bin/shShell zum Ausführen von Aufgaben. In einigen Distributionen ist dies ein Symlink zu dash. Keiner von beiden unterstützt die $RANDOMVariable, bei der es sich um eine bashspezifische Erweiterung handelt.

  • Mit vixie-cron können Sie eine Linie SHELL=/bin/bashoben auf Ihren crontab setzen.

  • Andernfalls müssen Sie sich mit bash -c 'echo $RANDOM'oder abfinden perl -e 'print int(rand(65535))'.

    (Im obigen Beispiel ist 65535 die maximale Anzahl, die zurückgegeben werden soll. Sie können auch andere Berechnungen im Skript anwenden.)

  • In einem ordnungsgemäß konfigurierten System wären Sie selbst darüber informiert worden cron- es sendet immer eine Jobausgabe, einschließlich Fehlermeldungen, per E-Mail. Installieren Sie einen leichten MTA.


Auch in Bash $(( ))ist gegenüber bevorzugt `expr`.

user1686
quelle
Zuletzt habe ich überprüft, dass /bin/shes sich nicht um eine tatsächliche Shell handelt, sondern lediglich um einen Symlink zur bevorzugten Shell des Systemadministrators (normalerweise Bash oder Dash) auf Debian.
Hallo71
1
@ Hello71: Was ich in der Post gesagt habe. Trotzdem ist es üblich, dass Systemsoftware aufgerufen wird /bin/sh(und erwartet, dass sie mit der Bourne-Shell kompatibel ist). Ein Beispiel ist die system()Funktion in glibc. Zeigt daher /bin/shnormalerweise auf die schnellste Bourne-kompatible Shell; und der Systemadministrator soll seine Präferenz in der entsprechenden Zeile von / etc / passwd
festlegen
@ Hello71: ... okay, meistens was ich in der Post gesagt habe. (Ich weiß , die meisten anderen Distributionen Link shzu bash, aber es schien nicht relevant.)
user1686
Sie haben Recht, /bin/shPunkte zu stürzen. Bis jetzt habe ich noch nie von Dash gehört. Ich habe es nachgeschlagen und es ist eine leichte Variante von Bash. Ich wusste auch nicht, dass Cron in einer "verkrüppelten" Umgebung läuft, aber es erklärt verschiedene andere Probleme, die ich in der Vergangenheit hatte. Übrigens habe ich angefangen zu benutzen, $(())aber da es nicht funktioniert hat, habe ich alle möglichen Variationen ausprobiert und bin am Ende dazu gekommen expr- was natürlich auch nicht funktioniert hat. Aber hier habe ich geendet :-) Ist es möglich, eine normale Bash-Shell ohne die Einschränkungen mit auszuführen bash -c 'xxxx'? Übrigens, ist es nicht möglich, Zeilenumbrüche in Kommentare einzufügen?
Marlar
@marlar: 1) dashist eine Shell. Es ist nicht mehr oder weniger normal als bash. Es ist auch keine Variante davon. 2) Siehe Punkte 1 und 2 in der Antwort.
user1686
2

cronWird normalerweise mit einer weniger "vollständigen" Umgebung ausgeführt, was bedeutet, dass Ihnen einfach nicht viele der gleichen Umgebungsvariablen zur Verfügung stehen. Anscheinend $RANDOMist dies einer der Fälle, und tatsächlich schlägt Ihr sleepBefehl aufgrund der undefinierten Variablen einfach mit einem Fehler fehl. Deshalb konnte Ihr Befehl überhaupt nicht ausgeführt werden, als Sie zu &&statt gewechselt haben ;. (Nun, eigentlich $RANDOMhandelt es sich um eine Bash-Funktion, die jedoch cronnicht in einer vollständigen Bash-Umgebung ausgeführt wird, in der diese Funktion offensichtlich fehlt.)

Um diese Aufgabe auszuführen, müssen Sie, wie gesagt, ein separates Bash-Skript verwenden. Alternativ können Sie möglicherweise eine Möglichkeit finden, die Sie cat /dev/urandomdirekt im cronBefehl verwenden können. Es ist jedoch wahrscheinlich einfacher, das, was Sie derzeit haben, in ein separates Bash-Skript zu verschieben.

Kromey
quelle
1
Es ist nicht schön, aber ich habe diese Lösung gefunden, die Ihrem Vorschlag entspricht: sleep $ (expr od -An -N1 -i /dev/urandom\% 30); Befehl
Marlar
1
$RANDOMist nicht Teil einer "vollständigen" Umgebung. Es hat nichts mit Umgebungsvariablen zu tun, die bei einem Prozessstart festgelegt wurden. Es ist eine spezielle Variable, die "on the fly" in bash erstellt wird. Sein neuer Wert wird immer generiert, wenn die Variable gelesen wird. --- cronVerwendet standardmäßig /bin/shauf Systemen, mit denen /bin/shkeine Verknüpfung besteht, bash $RANDOMstandardmäßig nicht.
Pabouk