Wie kann ich cron anweisen, jeden zweiten Tag einen Befehl auszuführen (ungerade / gerade)


45

Wenn Sie cron so konfigurieren, dass jeden zweiten Tag ein Befehl über das Feld "Tag des Monats" ausgeführt wird, gehen Sie wie folgt vor:

1 22 */2 * * COMMAND

Es läuft jedes Mal, wenn der Tag des Monats ungerade ist: 1,3,5,7,9 und so weiter.

Wie kann ich cron so konfigurieren, dass es an Tagen im Monat ausgeführt wird, die sogar 2,6,8,10 usw. entsprechen?

Antworten:


60

Die Syntax, die Sie ausprobiert haben, ist tatsächlich mehrdeutig. Abhängig von der Anzahl der Tage im Monat, werden einige Monate an ungeraden Tagen und einige an geraden Tagen ausgeführt. Dies liegt daran, dass die Art und Weise, wie sie berechnet wird, die Gesamtzahl der Möglichkeiten aufnimmt und sie aufteilt. Sie können dieses seltsame Verhalten umgehen, indem Sie den Tagesbereich manuell angeben und entweder eine ungerade oder eine gerade Anzahl von Tagen verwenden. Da Skripte mit geraden Tagen niemals am 31. Tag längerer Monate ausgeführt werden, verlieren Sie nichts, wenn Sie 30 Tage als Basis für gerade Tage verwenden. Wenn Sie angeben, dass die Aufteilung so erfolgen soll, als gäbe es 31 Tage, können Sie ungerade Werte erzwingen -tägige Ausführung.

Die Syntax würde folgendermaßen aussehen:

# Will only run on odd days:
0 0 1-31/2 * * command

# Will only run on even days:
0 0 2-30/2 * * command

Ihre Besorgnis über Monate, die nicht die gleiche Anzahl von Tagen haben, ist hier nicht wichtig, da keine Monate MEHR Tage als diese haben und der Datumsbereich für den schlechten Februar nicht immer mit dem oder den letzten beiden Tagen übereinstimmt, aber es schadet nichts es aufgelistet.

Das einzige "gotcha" für diesen Ansatz ist, dass, wenn Sie sich in einem ungeraden Tageszyklus befinden, nach Monaten mit 31 Tagen Ihr Befehl auch am Ersten des Monats ausgeführt wird. Wenn Sie einen geraden Zyklus erzwingen, führt jedes Schaltjahr zu einem dreitägigen Zyklus und Ende Februar. Sie können die Tatsache nicht wirklich umgehen, dass ein regelmäßiges Muster für "jeden zweiten Tag" nicht immer auf gerade oder ungerade Tage in jedem Monat fällt, und auf jede Weise, die Sie dies erzwingen, wird es entweder einen zusätzlichen Lauf geben oder einen Lauf dazwischen verpassen Monate mit fehlgeschlagenen Tageszählungen.


1
Danke, aber was passiert in Monaten wie Februar, in denen Sie nur 28 Tage haben? Der Stern kümmert sich tatsächlich darum - ist aber in der Tat mehrdeutig.
Freddie

3
@freddie: Siehe meine bearbeitete Antwort ... aber es ist kein Problem, da Werte außerhalb des Bereichs einfach ignoriert werden und am 30. oder 31. Februar nichts passiert. Je. Sie könnten manuell mit einer Liste wie angeben, 0,2,4...,30,32,34und es wäre egal, die Werte außerhalb des Bereichs würden einfach nie übereinstimmen.
Caleb

1
Vielen Dank! Ich verstehe, danke für die informative Antwort!
Freddie

3
Unter Ubuntu Server 8.04 scheint die Syntax mit dem Tag des Monats Null ungültig zu sein (falscher Tag des Monats). Die folgende Syntax wird jedoch akzeptiert:0 0 2-30/2 * * command

1
Fedora und RHEL 5,6,7 mögen auch nicht 0 als Tag des Monats. Wie user31053 betonte: Funktioniert 0 0 2-30/2 * * commandwie erwartet.
NoelProf

2

Ich denke, eine Möglichkeit besteht darin, den Tag des Jahres wie folgt zu verwenden:

# for odd days
test $(((`date +%j` % 2))) != 0 && command

# for even days
test $(((`date +%j` % 2))) == 0 && command

Es ist für Unix- und Linux-Systeme getestet.


Ich bevorzuge diese Antwort, weil das Problem mit der ungeraden Anzahl von Tagen mit einigen Monaten übersprungen wird. Wie auch immer, ich schlage stattdessen die Dollar-Notation vor:test $(($(date +%j) % 2)) == 0 && command
caligari

Ich habe überprüft, dass% j nicht das julianische Datum ist, daher muss der beste Code zur Vermeidung des Übergangs zum neuen Jahr in Sekunden berechnet werden:test $(($(date +%s) / 86400 % 2)) == 0 && command
caligari

Danke für die Kommentare! Unser Vorschlag wirkte für uns wie ein Zauber. Wir haben dieses Schema verwendet, um jeden Tag crons auf verschiedenen Serverknoten auszuführen, die alle dieselbe crontab verwenden, aber das Skript erlaubt nur das Ausführen des Skripts auf einem von ihnen. Wenn wir dies jedoch präzisieren müssen, werden wir Ihren Vorschlag prüfen. Vielen Dank!!!
Jordi

1

Lassen Sie uns jeden Tag überprüfen, ob es sich um ein "anderes" handelt :-) ( bcProgramm erforderlich)

0 0 * * * test $(echo `date +%s` / 86400 % 2 == 0 |bc) -eq 0 && command

(Ich bin nicht sicher, ob der Code korrekt angezeigt wird. Der date +%sTeil befindet sich zwischen Hochkommas.)


Dies wird jeden zweiten Tag ausgeführt, beantwortet jedoch nicht die Frage! Es wird manchmal an ungeraden Tagen ausgeführt, manchmal an geraden Tagen, je nach Monat. Dies hat dasselbe Ergebnis wie der Code in der Frage. Sie kommen nur zu dem Ergebnis, indem Sie Ihre eigenen Berechnungen für die Sekunden seit der Epoche anstellen. Dies geschieht an geraden Tagen seit der Epoche, jedoch nicht an geraden Tagen unseres Kalenders.
Caleb

1

Im Allgemeinen würde ich es jeden Tag ausführen und das Skript mithilfe von Logik bestimmen lassen, ob es heute ausgeführt werden soll.

Eine einfache Statusdatei zu erstellen, die angibt, wann sie zuletzt ausgeführt wurde, und dann zu vergleichen, würde sehr leicht funktionieren.

Wenn es durch verschiedene Quellen ausgeführt werden muss, machen Sie es argumentabhängig.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.