Ich habe aus einer Anweisung gelesen, am letzten Tag des Monats ein Skript zu planen:
Hinweis:
Der kluge Leser fragt sich möglicherweise, wie Sie einen Befehl festlegen können, der am letzten Tag eines jeden Monats ausgeführt wird, da Sie den Wert für den Tag des Monats nicht so einstellen können, dass er jeden Monat abdeckt. Dieses Problem hat Linux- und Unix-Programmierer geplagt und einige verschiedene Lösungen hervorgebracht. Eine übliche Methode besteht darin, eine if-then-Anweisung hinzuzufügen, die mit dem Befehl date prüft, ob das Datum von morgen 01 ist:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Dies überprüft jeden Tag um 12 Uhr, ob es der letzte Tag des Monats ist, und wenn ja, führt cron den Befehl aus.
Wie funktioniert das [`date +%d -d tomorrow` = 01 ]
?
Ist es richtig zu sagen then; command1
?
quelle
; endif
?[
und kein Leerzeichenfi
am Ende. Auch%
ist speziell in Crontabs.Antworten:
Abstrakt
Der richtige Code sollte sein:
Rufen Sie dieses Skript auf
end_of_month.sh
und der Aufruf in cron lautet einfach:Dadurch wird das Skript
end_of_month
(das intern überprüft, ob der Tag der letzte Tag des Monats ist) nur an den Tagen 28, 29, 30 und 31 ausgeführt. An keinem anderen Tag muss das Monatsende überprüft werden.Alter Beitrag.
Dies ist ein Zitat aus dem Buch "Linux Command Line and Shell Scripting Bible" von Richard Blum, Christine Bresnahan, S. 442, 3. Auflage, John Wiley & Sons © 2015.
Ja, das steht darin, aber das ist falsch / unvollständig:
fi
.[
und den folgenden`
.`…`
."$(…)"
;
Nachthen
Wie soll ich wissen? ( naja , aus Erfahrung ☺) aber Sie können Shellcheck ausprobieren . Fügen Sie den Code aus dem Buch ein (nach den Sternchen) und es werden Ihnen die oben aufgeführten Fehler sowie ein "fehlender Schebang" angezeigt. Ein Skript ohne Fehler in Shellcheck lautet wie folgt:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Diese Seite funktioniert, weil das, was geschrieben wurde, "Shell-Code" ist. Das ist eine Syntax, die in vielen Shells funktioniert.
Einige Probleme, die Shellcheck nicht erwähnt, sind:
Es wird davon ausgegangen, dass der Datumsbefehl die GNU-Datumsversion ist. Die mit einer
-d
Option, dietomorrow
als Wert akzeptiert wird (Busybox hat die Option -d, versteht sie aber morgen nicht und BSD hat eine-d
Option, bezieht sich jedoch nicht auf die "Anzeige" der Zeit).Es ist besser, das Format nach allen Optionen festzulegen
date -d tomorrow +'%d'
.Die Cron-Startzeit ist immer in der Ortszeit. Dies kann dazu führen, dass ein Job 1 Stunde früher als eine genaue Tageszählung startet, wenn die Sommerzeit eingestellt oder deaktiviert wurde.
Was wir gemacht haben, ist ein Shell-Skript, das mit cron aufgerufen werden könnte. Wir können das Skript weiter modifizieren, um Argumente des auszuführenden Programms oder Befehls wie folgt zu akzeptieren (schließlich den richtigen Code):
Rufen Sie dieses Skript auf
end_of_month.sh
und der Aufruf in cron lautet einfach:Dadurch wird das Skript
end_of_month
(das intern überprüft, ob der Tag der letzte Tag des Monats ist) nur an den Tagen 28, 29, 30 und 31 ausgeführt. An keinem anderen Tag muss das Monatsende überprüft werden.Stellen Sie sicher, dass der richtige Pfad enthalten ist. Der Pfad in cron ist (wahrscheinlich) nicht derselbe wie der Benutzerpfad.
Beachten Sie, dass ein Skript zum Monatsende getestet wurde (wie unten angegeben), das viele andere Dienstprogramme oder Skripte aufrufen kann.
Dadurch wird auch das zusätzliche Problem vermieden, das cron mit der vollständigen Befehlszeile generiert:
%
auch wenn sie entweder mit'
oder angegeben ist"
(\
hier funktioniert nur a ). Dies ist eine übliche Methode, mit der Cron-Jobs fehlschlagen.Sie können testen, ob das
end_of_month.sh
Skript an einem bestimmten Datum ordnungsgemäß funktioniert (ohne bis zum Ende des Monats zu warten, um festzustellen, dass es nicht funktioniert), indem Sie es mit faketime testen:quelle
date
(oder dasdate
eingebaute von ksh93, wenn ksh93 als Teil von ast-open gebaut wurde) unterstütztdate -d tomorrow +%s
oderdate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
nicht funktioniert, weil man vergessen hat, das zu zitieren\%
(was schwierig zu debuggen wird, wenn nur ein Versuch pro Monat möglich ist). @KusalanandaAngenommen, die Syntaxfehler sind behoben und der Befehl wurde leicht umformuliert, um weniger ausführlich zu sein:
Dies wird ausgeführt
date +%d -d tomorrow
(vorausgesetzt, es wird GNUdate
verwendet), um das morgige Datum als zweistellige Zahl abzurufen. Wenn die Nummer nicht ist01
, ist heute nicht der letzte Tag des Monats. In diesem Fall sind die Tests erfolgreich undcommand1
werden nicht ausgeführt. Der Job wird an den Tagen, die möglicherweise der letzte Tag des Monats sein könnten, mittags ausgeführt.Der ursprüngliche Befehl:
Dies hat einige Probleme:
[
.;
direkt danachthen
.%
ist speziell in Cron-Jobspezifikationen und muss als\%
(sieheman 5 crontab
) maskiert werden .fi
Ende gibt es kein Finale , das mit dem übereinstimmtif
.quelle
[ ... ] && command1
anstelle vonif...
besteht darin, dass an Tagen, die nicht der letzte Tag des Monats sind, der Cron-Job mit einem Exit-Status ungleich Null endet und dieser Fehler möglicherweise gemeldet werden muss. Die Verwendung[ "$(...)" != 01 ] || command1
ist ein weiterer Weg, um das Problem zu vermeiden.;
zwischenthen
undcommand1
."
oder'
(außer\
), das Prozentzeichen lässt%
cron die Linie in zwei Teile brechen. Das ist ein üblicher Weg, um Cron zum Scheitern zu bringen.Um den letzten Tag eines jeden Monats zu planen, können Sie Folgendes versuchen :
0 0 15,L * *
.quelle