Cron-Jobs und zufällige Zeiten innerhalb bestimmter Stunden

99

Ich brauche die Fähigkeit, ein PHP-Skript 20 Mal am Tag zu völlig zufälligen Zeiten auszuführen. Ich möchte auch, dass es nur zwischen 9 und 23 Uhr läuft.

Ich bin mit dem Erstellen von Cron-Jobs unter Linux vertraut.

floatleft
quelle
1
Die Frage ist nicht sehr gut gestellt. Letztendlich möchten Sie 20 Punkte auf der Zeitachse zwischen 9 und 11 Uhr verteilen. Aber gibt es Einschränkungen hinsichtlich des minimalen Zeitunterschieds? Ist es akzeptabel, zwischen 9 und 10:30 Uhr nichts zu tun? Der einzige Weg, dies akzeptabel zu tun, scheint Klaus 'Idee zu sein: Wählen Sie Ihre 20-mal um 09:00 Uhr aus, um eventuelle Einschränkungen zu erfüllen, und planen Sie dann die Dinge mit "at".
David Tonhofer

Antworten:

37

Wenn ich verstehe, wonach Sie suchen, müssen Sie etwas Unordentliches tun, z. B. einen Cron-Job, der ein Bash-Skript ausführt, das die Laufzeiten nach dem Zufallsprinzip ausführt.

crontab:

0 9 * * * /path/to/bashscript

und in / 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

Ein paar Anmerkungen: Dieser Ansatz verschwendet ein wenig Ressourcen, da er um 9 Uhr 20 Hintergrundprozesse auslöst, von denen jeder eine zufällige Anzahl von Minuten wartet (bis zu 14 Stunden, dh 23 Uhr), dann das PHP-Skript startet und Ausgänge. Da eine zufällige Anzahl von Minuten (nicht Sekunden) verwendet wird, sind die Startzeiten nicht ganz so zufällig, wie sie sein könnten. Aber $ RANDOM steigt nur auf 32.767 und es gibt 50.400 Sekunden zwischen 9 und 23 Uhr. Es wäre etwas komplizierter, die Sekunden ebenfalls zufällig zu ordnen. Da die Startzeiten zufällig und unabhängig voneinander sind, ist es möglich (aber nicht sehr wahrscheinlich), dass zwei oder mehr Instanzen des Skripts gleichzeitig gestartet werden.

Gordon Davisson
quelle
2
Sie können die arithmetischen Zuordnungen besser lesbar machen, indem Sie das Dollarzeichen fallen lassen und die Doppelparens nach links verschieben (z . B. ((maxdelay = 14 * 60))oder ((delay = $RANDOM % maxdelay))). Das sleepArgument muss immer noch so sein, wie Sie es haben (obwohl Sie auf Wunsch Leerzeichen hinzufügen können).
Bis auf weiteres angehalten.
Das hat auch bei mir funktioniert. Mein benutzerdefiniertes Bash-Skript sieht wie sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
folgt aus
Fehlt mir etwas oder sollte die maximale Verzögerung auf maxdelay = $ ((14 *
60/20
@jenishSakhiya Die zufälligen Verzögerungen für jeden der 20 Läufe sind absolut (also ab 9 Uhr morgens) und nicht relativ zu einem anderen der Läufe. Das heißt, wenn eine der zufälligen Verzögerungen 13 Stunden beträgt, bedeutet dies, dass sie um 22 Uhr (13 Stunden nach 9 Uhr) und nicht 13 Stunden nach einem der anderen Läufe ausgeführt wird.
Gordon Davisson
138

Ja, ja, die Frage ist über ein Jahr alt, aber vielleicht kann ich etwas Nützliches hinzufügen:

Wie kann man zwischen 9 und 23 Uhr 20 Mal am Tag einen zufälligen Versatz erstellen? Das ist in cron etwas schwierig, weil Sie 14 Stunden durch 20 Ausführungszeiten teilen. Ich mag die anderen Antworten nicht sehr, weil sie das Schreiben eines Bash-Wrapper-Skripts für Ihr PHP-Skript erfordern.

Wenn Sie mir jedoch die Freiheit geben, die Zeit- und Frequenzbeschränkung zwischen 8:30 Uhr und 23:09 Uhr auf 13 Mal zu lockern, könnte dies den Trick tun, und das alles innerhalb der Grenzen Ihrer Crontab:

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

$ {RANDOM: 3: 2} verwendet Bashs $ RANDOM, das andere oben erwähnt haben, fügt jedoch das Bashing-Array-Slicing hinzu. Da Bash-Variablen untypisiert sind, wird die pseudozufällig vorzeichenbehaftete 16-Bit-Zahl auf die ersten 2 ihrer 5 Dezimalstellen gekürzt, sodass Sie einen prägnanten Einzeiler erhalten, mit dem Sie Ihren Cronjob zwischen 10 und 99 Minuten verzögern können (obwohl die Verteilung voreingenommen ist) 10 bis 32).

Das Folgende könnte auch für Sie funktionieren, aber ich fand es aus irgendeinem Grund "weniger zufällig" (vielleicht wird Benfords Gesetz durch die Modulation von Pseudozufallszahlen ausgelöst. Hey, ich weiß nicht, ich bin durchgefallen ... Beschuldigen Sie es auf bash!):

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

Sie müssen den Modul oben als '\%' rendern, da cron (zumindest Linux 'vixie-cron') die Zeile beendet, wenn es auf ein nicht entflohenes '%' stößt.

Vielleicht könnten Sie die verbleibenden 7 Skriptausführungen dort erhalten, indem Sie eine weitere Zeile mit einem weiteren 7-Stunden-Bereich hinzufügen. Oder lockern Sie Ihre Einschränkung, um zwischen 3 und 23 Uhr zu laufen.

al-x
quelle
4
Ich mag die späte Antwort. Wenn Sie jedoch versuchen, eine zufällige Ganzzahl zu generieren, die gleichmäßig im Bereich von 10 bis 99 verteilt ist und die Ausgabe von RANDOM zwischen 0 und 32.767 liegt, warum sollten Sie dies nicht einfach tun $[(RANDOM/368)+10]?
Jsdalton
3
@jsdalton: Wäre der Modulo-Operator nicht besser? $((RANDOM % 90 + 10))Test:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
Geon
5
Auf vielen Systemen verwendet cron standardmäßig nicht bash, daher ist es möglicherweise besser, den bashism zu vermeiden $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
Pabouk
9
Stellen Sie sicher, dass verwendet crontabwird, bashbevor Sie verwenden $RANDOM. Wenn Sie haben vixie-cron(scheint mein Fall auf Ubuntu zu sein), dann können Sie SHELL=/bin/bashnach oben hinzufügen . Es gibt mehr Alternativen für andere Cron - Versionen hier: superuser.com/a/264541/260350
DaAwesomeP
1
Wenn ich den ersten Vorschlag oben verwende, bekomme ich crontab: errors in crontab file, can't install. Do you want to retry the same edit?bitte Hilfe
Seano
71

Daher verwende ich Folgendes, um einen Befehl zwischen 1 Uhr morgens und 330 Uhr morgens auszuführen

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

Das hat sich um meine zufälligen Bedürfnisse für mich gekümmert. Das sind 9000 Sekunden == 150 Minuten == 2,5 Stunden

Dave
quelle
8
:: MindBLOWN :: ein weiterer dunkler Ort, an dem man ein bisschen Perl verwenden kann.
Mark Carpenter Jr
Dies ist definitiv die sauberste Antwort
Enrico Detoma
21

Cron bietet eine RANDOM_DELAYVariable an. Siehe crontab(5)für Details.

Die Variable RANDOM_DELAY ermöglicht die Verzögerung von Jobstarts um eine zufällige Anzahl von Minuten, wobei die Obergrenze durch die Variable angegeben wird.

Dies wird häufig in anacronJobs gesehen, kann aber auch in a nützlich sein crontab.

Möglicherweise müssen Sie damit vorsichtig sein, wenn Sie einige Jobs haben, die mit feiner (Minuten-) Granularität ausgeführt werden, und andere, die grob sind.

Micah Elliott
quelle
Ich würde gerne die Variable RANDOM_DELAY verwenden, kann aber keinen Hinweis in der Manpage von crontab (5) unter Ubuntu 14.04.4 LTS finden.
Exocom
Das ist bedauerlich. Ich frage mich, ob es dort nicht unterstützt wird. Ich sehe es in dieser Manpage unter Centos 7 und Arch Linux dokumentiert.
Micah Elliott
9
Dies scheint die richtige Antwort zu sein, aber können Sie ein Beispiel geben?
Chovy
14
Bitte beachten Sie, dass dies RANDOM_DELAYeinmal eingerichtet ist und für die gesamte Laufzeit des Daemons konstant bleibt.
Maciej Swic
5
Die RANDOM_DELAYFlagge ist ein Merkmal von cronie-crond, während Ubuntu zu laufen scheint, vixie-crondem diese Flagge fehlt.
Kravietz
7

Mein erster Gedanke wäre, einen Cron-Job zu erstellen, der 20 zufällig geplante Jobs startet. Das atDienstprogramm (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) wird zum Ausführen von Befehlen zu einem bestimmten Zeitpunkt verwendet.

klaus
quelle
Ein Beispiel für die Verwendung von at ist hier: stackoverflow.com/a/6136145/803174
Kangur
6

Am Ende habe ich verwendet sleep $(( 1$(date +%N) % 60 )) ; dostuffs(kompatibel mit bash & sh)

Das Präfix 1 soll die Interpretation des Datums +% N durch NON Base 8 erzwingen (z. B. 00551454).

Vergessen Sie nicht,% mit \% in einer Crontab-Datei zu maskieren

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 
131
quelle
2
Wenn sich jemand wie ich fragt:% N liefert aktuelle Nanos, aber einigen Manpages fehlen Informationen dafür. Dies ist eine sehr clevere Lösung für Leute, die nur leicht "etwas Zufälligkeit" pro Befehl benötigen.
Thorsten Schöning
Abgesehen von den bereits an anderer Stelle behandelten Einschränkungen funktioniert dies nur, wenn Sie über GNU verfügen date(was Sie wahrscheinlich auf den meisten Linux-Systemen tun, jedoch nicht auf Busybox, Standard-MacOS oder verschiedenen anderen von BSD abgeleiteten Plattformen).
Tripleee
4

Die Lösung von al-x funktioniert bei mir nicht, da crontab-Befehle nicht in bash ausgeführt werden, sondern in sh, denke ich. Was funktioniert ist:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py
Wilbert
quelle
Ich habe alles versucht und es hat bei mir immer noch nicht funktioniert. Du postest erklärt warum, danke!
Marlar
$[ ... ]ist veraltete Syntax seit waaaay zurück; Für alles aus diesem Jahrtausend würden Sie eine $((RANDOM\%90))mPOSIX-kompatible Syntax bevorzugen (aber natürlich RANDOMimmer noch nur Bash).
Tripleee
1

at -f [file] [timespec]

oder

echo [command] | at [timespec]

oder

at [timespec]... und interaktive Spezifikation wie scriptdie Aufnahme.

Befehl

Bei Ausführungen wird der Text auf stdin oder in der durch angegebenen Datei bereitgestellt -f [file].

Timespec

Hier ist die [timespec] Grammatik . Es kann so etwas sein wie:

  • 24-Stunden - Zeit als 4-stellige int, zum Beispiel 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Wenn Sie die Zeitzone explizit angeben , lassen einige Versionen der Zeitspezifikation möglicherweise nur UTCdas optionale Zeitzonenargument zu.

Beispiel

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

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

Versuch es...

Sie können die Bash-Analyse testen, echoindem Sie die |(Pipe) vorab anstehen und verlassen .

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

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

Um geplante Jobs anzuzeigen, verwenden Sie atqund Jobinhalte (Umgebungsvariablen, Setup und Befehl / Skript) mit at -c [jobid].

Hinweis

Das System ist Teil von cron, und die interaktive Eingabeaufforderung erfasst tatsächlich den gesamten aktuellen Status Ihrer Shell, sodass Sie Befehle ausführen können, ohne absolute Pfade anzugeben.

mcint
quelle
0

Für diejenigen, die den Weg hierher gegoogelt haben:

Wenn Sie Anacron (Ubuntu Desktop und Laptop) verwenden, können Sie bearbeiten

/etc/anacrontab

und hinzufügen

RANDOM_DELAY=XX 

Dabei ist XX die Anzahl der Minuten, die Sie den Basisjob verzögern möchten.

Anacron ist wie Cron, erwartet jedoch nicht, dass Ihr Computer rund um die Uhr verfügbar ist (wie unsere Laptops), und führt die Skripte aus, die aufgrund eines Systemausfalls übersehen wurden.

Ganesh Krishnan
quelle
0

Sie können mit diesem Beispiel versuchen, zufällige Zeiten zu verwenden, bevor Sie den Befehl ausführen:

#!/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
quelle
0

Was ist mit dem Erstellen eines Skripts, das die Crontab jeden Tag neu schreibt?

  1. Aktuelle Crones lesen (A)
  2. Wähle zufällige Zeiten (B)
  3. Schreiben Sie frühere Cron (A) neu und fügen Sie neue zufällige Cron (B) hinzu.
  4. Stellen Sie sicher, dass Sie dem Cron hinzufügen, um dieses Skript auszuführen.
Mellofellow
quelle
2
Umgehen Sie das Reputationssystem nicht, indem Sie Kommentare als Antworten veröffentlichen. Ihr Kommentar ist aber gut genug aussehen , um tatsächlich zu sein , eine Antwort. Ich empfehle, " Ich habe keinen Repräsentanten, um einen Kommentar hinzuzufügen, aber " zu entfernen .
Ted Lyngmo
1
Ich habe gerade diese Antwort überprüft und den Teil verpasst, in dem Sie am Ende eine Frage stellen (schlampige Arbeit meinerseits). Stellen Sie keine Fragen in Antworten. Stellen Sie Ihre eigene Frage für Fragen, die Sie haben. Ich habe Ihre Halbfrage zu etwas gemacht, das als Antwort durchgehen könnte.
Ted Lyngmo
1
Verstanden! Vielen Dank. Ich werde das nächste Mal vorsichtiger sein, es war keine schlechte Absicht gemeint.
Mellofellow
1
Ich bin sicher, Sie hatten keine bösen Absichten und müssen nicht übermäßig vorsichtig sein. Sie haben eine mögliche Lösung skizziert - und sind am Ende ein bisschen gestolpert. Keine Sorge!
Ted Lyngmo
0

Mir ist klar, dass es sich um einen älteren Thread handelt, aber ich möchte eine Sache mit zufälligen Werten hinzufügen, die ich häufig verwende. Anstatt die Variable $ RANDOM mit einem festen und begrenzten Bereich zu verwenden, mache ich häufig Zufallswerte mit beliebigem Bereich in der Shell mit

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

so können Sie zum Beispiel tun,

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

und überwinden Sie einige der Einschränkungen, die in diesem Thread diskutiert wurden.

MLP
quelle
1
Willkommen bei SO. Nun, alter Thread oder nicht, das hat mich losgeschickt ~$info ddund ich kann verstehen, was auf der linken Seite los |ist, kann aber die rechte Seite nicht erkennen. overcoming some restrictionsNehmen Sie sich für mich und andere, die an der Erzeugung zufälliger Werte interessiert sind , einen Moment Zeit, um die RHS zu erklären, und machen Sie eine stärkere Tonhöhe für die Verwendung Ihres Ansatzes. Die Tiefe der Erklärung macht es den Menschen sowohl mit dem von Ihnen vorgeschlagenen Prozess als auch mit seinen Vorteilen angenehm. Danke.
Chris
Ah ok. od aka "octal dump" nimmt eine Datei oder stdin und speichert die Binärdaten in lesbarer Form. Wir möchten, dass unsere Zahl als vorzeichenlose Dezimalzahl (-t u4) angezeigt wird, und wir möchten nicht, dass der Adressindex (-A none) angezeigt wird. Das -N4 ist redundant, da wir nur 4 Bytes benötigen, aber es tut auch nicht weh. Ich hoffe das erklärt es ...
MLP