GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum funktioniert mein Crontab nicht und wie kann ich es beheben?

Lösung 1:

So beheben Sie alle Probleme/Probleme im Zusammenhang mit Crontab (Linux)

Dies ist ein Community-Wiki. Wenn Sie an dieser Antwort etwas Falsches bemerken oder zusätzliche Informationen haben, bearbeiten Sie sie bitte.

Zuerst grundlegende Terminologie:

  • cron(8) ist der Daemon, der geplante Befehle ausführt.
  • crontab(1) ist das Programm, das verwendet wird, um Benutzer-crontab(5)-Dateien zu ändern.
  • crontab(5) ist eine benutzerspezifische Datei, die Anweisungen für cron(8) enthält.

Als nächstes Informationen zu Cron:

Jeder Benutzer auf einem System kann seine eigene crontab-Datei haben. Der Speicherort der Root- und Benutzer-crontab-Dateien ist systemabhängig, liegt aber im Allgemeinen unter /var/spool/cron .

Es gibt einen systemweiten /etc/crontab Datei, die /etc/cron.d Das Verzeichnis kann crontab-Fragmente enthalten, die auch von cron gelesen und verarbeitet werden. Einige Linux-Distributionen (z. B. Red Hat) haben auch /etc/cron.{hourly,daily,weekly,monthly} das sind Verzeichnisse, darin enthaltene Skripte, die jede Stunde/Tag/Woche/Monat mit Root-Rechten ausgeführt werden.

root kann immer den crontab-Befehl verwenden; normalen Benutzern kann Zugriff gewährt werden oder nicht. Wenn Sie die Crontab-Datei mit dem Befehl crontab -e bearbeiten und speichern, crond prüft es auf grundsätzliche Gültigkeit, garantiert aber nicht, dass Ihre crontab-Datei korrekt aufgebaut ist. Es gibt eine Datei namens cron.deny wodurch angegeben wird, welche Benutzer cron nicht verwenden können. Die cron.deny Der Speicherort der Datei ist systemabhängig und kann gelöscht werden, sodass alle Benutzer cron verwenden können.

Wenn der Computer nicht eingeschaltet ist oder der crond-Daemon nicht läuft und das Datum/die Uhrzeit für die Ausführung eines Befehls abgelaufen ist, wird crond nicht aufholen und frühere Abfragen ausführen.

Crontab-Besonderheiten, wie man einen Befehl formuliert:

Ein crontab-Befehl wird durch eine einzelne Zeile dargestellt. Sie können \ nicht verwenden um einen Befehl über mehrere Zeilen zu erweitern. Der Hash (# ) stellt einen Kommentar dar, was bedeutet, dass alles in dieser Zeile von cron ignoriert wird. Führende Leerzeichen und Leerzeilen werden ignoriert.

Seien Sie SEHR vorsichtig, wenn Sie den Prozentsatz verwenden (% ) Melden Sie sich in Ihrem Befehl an. Es sei denn, sie sind \% maskiert sie werden in Zeilenumbrüche umgewandelt und alles nach dem ersten nicht maskierten % wird an Ihren Befehl auf stdin übergeben.

Es gibt zwei Formate für Crontab-Dateien:

  • Benutzer-Crontabs

     # Example of job definition:
     # .---------------- minute (0 - 59)
     # |  .------------- hour (0 - 23)
     # |  |  .---------- day of month (1 - 31)
     # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
     # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
     # |  |  |  |  |
     # *  *  *  *  *   command to be executed
    
  • Systemweit /etc/crontab und /etc/cron.d Fragmente

     # Example of job definition:
     # .---------------- minute (0 - 59)
     # |  .------------- hour (0 - 23)
     # |  |  .---------- day of month (1 - 31)
     # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
     # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
     # |  |  |  |  |
     # *  *  *  *  * user-name  command to be executed
    

Beachten Sie, dass letzteres einen Benutzernamen erfordert. Der Befehl wird als benannter Benutzer ausgeführt.

Die ersten 5 Felder der Zeile stellen die Zeit(en) dar, zu denen der Befehl ausgeführt werden soll. Sie können Zahlen oder ggf. Tages-/Monatsnamen in der Zeitangabe verwenden.

  • Die Felder sind durch Leerzeichen oder Tabulatoren getrennt.
  • Ein Komma (, ) wird verwendet, um eine Liste anzugeben, z. B. 1,4,6,8, was bedeutet, dass sie bei 1,4,6,8 ausgeführt wird.
  • Bereiche werden mit einem Bindestrich angegeben (- ) und kann mit Listen kombiniert werden, z. 1-3,9-12, was zwischen 1 und 3 bedeutet, dann zwischen 9 und 12.
  • Die / kann verwendet werden, um einen Schritt einzuleiten, z. 2/5, was bedeutet, beginnend bei 2 dann alle 5 (2,7,12,17,22...). Sie gehen nicht über das Ende hinaus.
  • Ein Sternchen (* ) in einem Feld gibt den gesamten Bereich für dieses Feld an (z. B. 0-59 für das Minutenfeld).
  • Bereiche und Schritte können kombiniert werden, z.B. */2 bedeutet beginnend mit dem Minimum für das relevante Feld dann alle 2 z.B. 0 für Minuten (0,2...58), 1 für Monate (1,3...11) usw.

Debuggen von Cron-Befehlen

Check die Post!

Standardmäßig sendet cron alle Ausgaben des Befehls an den Benutzer, unter dem er den Befehl ausführt. Wenn keine Ausgabe erfolgt, wird keine E-Mail gesendet. Wenn Sie möchten, dass Cron E-Mails an ein anderes Konto sendet, können Sie die Umgebungsvariable MAILTO in der Crontab-Datei festlegen, z. B.

[email protected]
1 2 * * * /path/to/your/command

Erfassen Sie die Ausgabe selbst

Sie können stdout und stderr in eine Datei umleiten. Die genaue Syntax zum Erfassen der Ausgabe kann je nach verwendetem Shell-Cron variieren. Hier sind zwei Beispiele, die alle Ausgaben in einer Datei unter /tmp/mycommand.log speichern :

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

Sehen Sie sich die Protokolle an

Cron protokolliert seine Aktionen über Syslog, die (je nach Konfiguration) oft an /var/log/cron gehen oder /var/log/syslog .

Bei Bedarf können Sie die Cron-Anweisungen filtern, z. B. mit

grep CRON /var/log/syslog 

Nachdem wir nun die Grundlagen von Cron besprochen haben, wo sich die Dateien befinden und wie man sie verwendet, wollen wir uns einige häufig auftretende Probleme ansehen.

Überprüfen Sie, ob Cron ausgeführt wird

Wenn cron nicht läuft, werden Ihre Befehle nicht geplant ...

ps -ef | grep cron | grep -v grep

sollte Ihnen so etwas bringen wie

root    1224   1  0 Nov16 ?    00:00:03 cron

oder

root    2018   1  0 Nov14 ?    00:00:06 crond

Wenn nicht, starten Sie es neu

/sbin/service cron start

oder

/sbin/service crond start

Es kann andere Methoden geben; Verwenden Sie, was Ihre Distribution bereitstellt.

cron führt Ihren Befehl in einer eingeschränkten Umgebung aus.

Welche Umgebungsvariablen verfügbar sind, ist wahrscheinlich sehr begrenzt. Normalerweise werden nur wenige Variablen definiert, z. B. $LOGNAME , $HOME , und $PATH .

Besonders hervorzuheben ist der PATH ist auf /bin:/usr/bin beschränkt . Die überwiegende Mehrheit der "Mein Cron-Skript funktioniert nicht"-Probleme werden durch diesen restriktiven Pfad verursacht . Wenn sich Ihr Befehl an einem anderen Ort befindet, können Sie dies auf verschiedene Arten lösen:

  1. Geben Sie den vollständigen Pfad zu Ihrem Befehl an.

     1 2 * * * /path/to/your/command
    
  2. Geben Sie in der crontab-Datei einen geeigneten PATH an

     PATH=/bin:/usr/bin:/path/to/something/else
     1 2 * * * command 
    

Wenn Ihr Befehl andere Umgebungsvariablen erfordert, können Sie diese auch in der crontab-Datei definieren.

cron führt Ihren Befehl mit cwd ==$HOME

aus

Unabhängig davon, wo sich das Programm, das Sie ausführen, im Dateisystem befindet, ist das aktuelle Arbeitsverzeichnis des Programms, wenn cron es ausführt, das Home-Verzeichnis des Benutzers . Wenn Sie in Ihrem Programm auf Dateien zugreifen, müssen Sie dies berücksichtigen, wenn Sie relative Pfade verwenden, oder (vorzugsweise) überall nur vollständig qualifizierte Pfade verwenden, und allen eine Menge Verwirrung ersparen.

Der letzte Befehl in meiner Crontab wird nicht ausgeführt

Cron erfordert im Allgemeinen, dass Befehle mit einer neuen Zeile abgeschlossen werden. Bearbeiten Sie Ihre Crontab; Gehen Sie zum Ende der Zeile, die den letzten Befehl enthält, und fügen Sie eine neue Zeile ein (drücken Sie die Eingabetaste).

Überprüfen Sie das Crontab-Format

Sie können keine Crontab im Benutzer-Crontab-Format für /etc/crontab oder die Fragmente in /etc/cron.d verwenden und umgekehrt. Eine benutzerformatierte Crontab enthält keinen Benutzernamen an der 6. Position einer Zeile, während eine systemformatierte Crontab den Benutzernamen enthält und den Befehl als dieser Benutzer ausführt.

Ich habe eine Datei in /etc/cron.{hourly,daily,weekly,monthly} abgelegt und sie läuft nicht

  • Überprüfen Sie, dass der Dateiname keine Erweiterung hat, siehe Run-Parts
  • Stellen Sie sicher, dass die Datei Ausführungsberechtigungen hat.
  • Teilen Sie dem System mit, was es beim Ausführen Ihres Skripts verwenden soll (geben Sie z. B. #!/bin/sh ein oben)

Crondate-bezogene Fehler

Wenn Ihr Datum kürzlich durch ein Benutzer- oder Systemupdate, eine Zeitzone oder anderes geändert wurde, wird crontab anfangen, sich unregelmäßig zu verhalten und bizarre Fehler aufweisen, die manchmal funktionieren, manchmal nicht. Dies ist der Versuch von crontab zu versuchen, "das zu tun, was Sie wollen", wenn sich die Zeit darunter ändert. Das Feld „Minute“ wird nach Änderung der Stunde unwirksam. In diesem Szenario würden nur Sternchen akzeptiert. Starten Sie cron neu und versuchen Sie es erneut, ohne sich mit dem Internet zu verbinden (damit das Datum nicht auf einen der Zeitserver zurückgesetzt werden kann).

Wieder Prozentzeichen

Um den Ratschlag zu Prozentzeichen hervorzuheben, hier ein Beispiel dafür, was cron damit macht:

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

erstellt die Datei ~/cron.out mit den 3 Zeilen

foo
bar
baz

Dies ist besonders aufdringlich, wenn der date verwendet wird Befehl. Stellen Sie sicher, dass Sie die Prozentzeichen maskieren

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"

Vorsicht vor Sudo

beim Ausführen als Nicht-Root-Benutzer,

crontab -e

öffnet die Crontab des Benutzers, während

sudo crontab -e

öffnet die Crontab des Root-Benutzers. Es wird nicht empfohlen, sudo-Befehle in einem Cron-Job auszuführen. Wenn Sie also versuchen, einen sudo-Befehl im Cron eines Benutzers auszuführen, versuchen Sie, diesen Befehl in den Cron von root zu verschieben, und entfernen Sie sudo aus dem Befehl.

Lösung 2:

Debian Linux und seine Derivate (Ubuntu, Mint usw.) haben einige Eigenheiten, die die Ausführung Ihrer Cron-Jobs verhindern können. insbesondere die Dateien in /etc/cron.d , /etc/cron.{hourly,daily,weekly,monthly} muss :

  • im Besitz von root sein
  • nur von root beschreibbar sein
  • nicht von Gruppen oder anderen Benutzern beschreibbar sein
  • haben einen Namen ohne Punkte '.' oder jedes andere Sonderzeichen außer '-' und '_' .

Letzteres verletzt regelmäßig ahnungslose Benutzer; insbesondere jedes Skript in einem dieser Ordner namens whatever.sh , mycron.py , testfile.pl usw. werden nicht hingerichtet werden, jemals.

Dieser spezielle Punkt war meiner Erfahrung nach der mit Abstand häufigste Grund für einen nicht ausgeführten Cronjob auf Debian und Derivaten.

Siehe man cron für weitere Details, falls erforderlich.

Lösung 3:

Wenn Ihre Cronjobs nicht mehr funktionieren, überprüfen Sie, ob Ihr Passwort abgelaufen ist, denn sobald es abgelaufen ist, werden alle Cronjobs angehalten.
Es wird Nachrichten in /var/log/messages geben ähnlich der folgenden, die Probleme mit der Authentifizierung des Benutzers zeigt:

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)

Lösung 4:

Ungewöhnliche und unregelmäßige Zeitpläne

Cron ist alles in allem ein sehr einfacher Scheduler und die Syntax erlaubt es einem Administrator nicht ohne weiteres, etwas ungewöhnlichere Zeitpläne zu formulieren.

Betrachten Sie den folgenden Job, der üblicherweise erklärt werden würde zu "command ausführen alle 5 Minuten" :

*/5 * * * * /path/to/your/command

gegen:

*/7 * * * * /path/to/your/command

was nicht immer tut Führen Sie command aus alle 7 Minuten .

Denken Sie daran, dass die / kann verwendet werden, um einen Schritt einzuleiten, aber diese Schritte enden nicht über das Ende einer Reihe hinaus, z. */7 was jede 7. Minute ab den Minuten 0-59 entspricht also 0,7,14,21,28,35,42,49,56 aber zwischen einer Stunde und der nächsten zwischen den Chargen liegen nur 4 Minuten , nach 00:56 eine neue Serie beginnt bei 01:00 , 01:07 usw. (und Batches werden nicht auf 01:03 ausgeführt , 01:10 , 01:17 usw.).

Was stattdessen tun?

Erstellen Sie mehrere Stapel

Erstellen Sie statt eines einzelnen Cron-Jobs mehrere Batches, die zusammen den gewünschten Zeitplan ergeben.

Um beispielsweise alle 40 Minuten einen Batch auszuführen (00:00, 00:40, 01:20, 02:00 usw.), erstellen Sie zwei Batches, einen, der zweimal zu den geraden Stunden ausgeführt wird, und einen zweiten, der nur zu den ungeraden Stunden ausgeführt wird:

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

Lassen Sie Ihre Batches seltener laufen

Anstatt Ihren Batch alle 7 Minuten auszuführen, was ein schwieriger Zeitplan ist, um ihn in mehrere Batches aufzuteilen, führen Sie ihn stattdessen einfach alle 10 Minuten aus.

Starten Sie Ihre Chargen häufiger (aber verhindern, dass mehrere Batches gleichzeitig ausgeführt werden)

Viele ungerade Zeitpläne entwickeln sich, weil die Batch-Laufzeiten zunehmen/schwanken und die Batches dann mit einem kleinen zusätzlichen Sicherheitsspielraum geplant werden, um zu verhindern, dass nachfolgende Läufe desselben Batches sich überschneiden und gleichzeitig ausgeführt werden.

Denken Sie stattdessen anders und erstellen Sie einen Cronjob, der ordnungsgemäß fehlschlägt, wenn ein vorheriger Lauf noch nicht beendet ist, der aber ansonsten ausgeführt wird. Siehe diese Fragen und Antworten:

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

Dadurch wird fast sofort ein neuer Lauf gestartet, sobald der vorherige Lauf von /usr/local/bin/frequent_cron_job abgeschlossen ist.

Starten Sie Ihre Chargen häufiger (aber elegant beenden, wenn die Bedingungen nicht stimmen)

Da die Cron-Syntax begrenzt ist, können Sie entscheiden, komplexere Bedingungen und Logik in den Batch-Job selbst zu platzieren (oder in einem Wrapper-Skript um den vorhandenen Batch-Job). Dadurch können Sie die erweiterten Fähigkeiten Ihrer bevorzugten Skriptsprachen nutzen, Ihren Code kommentieren und schwer lesbare Konstrukte im crontab-Eintrag selbst verhindern.

In bash der seven-minute-job würde dann in etwa so aussehen:

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below
  
/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

Was Sie dann sicher jede Minute ausführen (versuchen) können:

* * * * * /path/to/your/seven-minute-job

Ein anderes, aber ähnliches Problem wäre, einen Batch so zu planen, dass er am ersten Montag jedes Monats (oder am zweiten Mittwoch) usw. ausgeführt wird. Planen Sie einfach, dass der Batch jeden Montag ausgeführt und beendet wird, wenn das Datum weder zwischen 1 noch 7 und dem Tag liegt der Woche ist nicht der Montag.

#!/bin/bash
# first-monday-of-the-month-housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below
  
/path/to/your/command

#EOF

Was Sie dann sicher jeden Montag ausführen (versuchen) können:

0 0 * * 1 /path/to/your/first-monday-of-the-month-housekeeping-job

Cron nicht verwenden

Wenn Ihre Anforderungen komplex sind, sollten Sie ein fortschrittlicheres Produkt verwenden, das für die Ausführung komplexer Zeitpläne (auf mehrere Server verteilt) ausgelegt ist und Trigger, Jobabhängigkeiten, Fehlerbehandlung, Wiederholungen und Wiederholungsüberwachung usw. unterstützt. Der Branchenjargon wäre „Enterprise " Job Scheduling und/oder "Workload Automation".

Lösung 5:

PHP-spezifisch

Wenn Sie einen Cron-Job haben wie:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

Und im Falle von Fehlern erwarten Sie, dass sie Ihnen zugesandt werden, aber sie nicht -- überprüfen Sie dies.

PHP sendet standardmäßig keine Fehler an STDOUT. @siehe https://bugs.php.net/bug.php?id=22839

Um dies zu beheben, fügen Sie Folgendes in cli`s php.ini oder in Ihrer Zeile (oder in Ihrem Bash-Wrapper für PHP) hinzu:

  • --define display_startup_errors=1
  • --define display_errors='stderr'

Die 1. Einstellung ermöglicht es Ihnen, fatale Meldungen wie „Memory oops“ zu haben und die 2. – sie alle auf STDERR umzuleiten. Erst danach können Sie gut schlafen, da alles an die Mail Ihres Roots gesendet wird, anstatt nur protokolliert zu werden.


Linux
  1. Wie kann ich ls nach Besitzer und Gruppe sortieren?

  2. Wie kann ich in Ubuntu 10.04 eine Sudo-Sitzung zu einer Stunde und nicht zu wenigen Minuten machen?

  3. Wie kann ich 'diff -X' dazu bringen, bestimmte Pfade und keine Dateinamen zu ignorieren?

  4. Woher weiß ich, ob netcat &dd funktionieren?

  5. Warum verwenden wir su - und nicht nur su?

Redis als Cache:Wie es funktioniert und warum man es verwendet

So finden Sie heraus, ob ein Paket unter Linux und Unix installiert ist oder nicht

Warum kann ich eine .ape-Datei nicht teilen?

Warum ist es Rm -rf und nicht Rmdir -rf?

Wie können Fernarbeit und Planung der Geschäftskontinuität die Auswirkungen von COVID-19 (Coronavirus) abmildern?

Wie und warum Linux zur Installation von Telnet verwendet wird