Frage Einen Cron-Job manuell und sofort ausführen


(Ich habe es schon gelesen Wie kann ich ein neues Cron-Skript testen?.)

Ich habe ein spezifisches Problem (Cron-Job scheint nicht ausgeführt zu werden oder richtig ausgeführt zu werden), aber das Problem ist allgemein: Ich möchte Skripte debuggen, die cronned sind. Mir ist bewusst, dass ich eine Crontab-Linie * * * * * einrichten kann, aber das ist keine vollkommen zufriedenstellende Lösung. Ich würde gerne in der Lage sein, einen Cron-Job von der Kommandozeile aus zu starten, als würde Cron ihn ausführen (gleicher Benutzer, gleiche Umgebungsvariablen, etc.). Gibt es eine Möglichkeit, dies zu tun? Warten auf 60 Sekunden, um Skriptänderungen zu testen, ist nicht praktikabel.


94
2017-11-18 13:55


Ursprung


(Entschuldigung, kann keinen Kommentar hinzufügen) 0 30 16 20 *? * Selbst wenn Sie den Job so ausführen, besteht die ganze Idee darin, eine Skriptausgabe zu liefern, um zu sehen, was schief läuft, wenn der Job nicht in ein Protokoll schreibt, das ist quuiet nutzlos


Antworten:


Hier ist, was ich getan habe, und es scheint in dieser Situation zu funktionieren. Zumindest zeigt es mir einen Fehler, während von der Befehlszeile ausgeführt wird, da der Benutzer den Fehler nicht anzeigt.


Schritt 1: Ich habe diese Zeile vorübergehend in die crontab des Benutzers eingefügt:

* * * * *   /usr/bin/env > /home/username/tmp/cron-env

nahm es dann heraus, sobald die Datei geschrieben wurde.

Schritt 2: Habe mir ein kleines run-as-cron Bash-Skript erstellt, das folgendes enthält:

#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"

Also, als der Benutzer in Frage war, konnte ich

run-as-cron /the/problematic/script --with arguments --and parameters

Diese Lösung könnte natürlich erweitert werden, um sudo oder dergleichen für mehr Flexibilität zu nutzen.

Hoffe das hilft anderen.


73
2017-11-18 14:40



Das funktioniert nicht für mich, und ich frage mich, ob es für jeden, der aufgestanden ist, tut. 1) Warum benutzt du bash? Es ist hier nicht erforderlich und möglicherweise nicht in /usr/bin. 2) Die cat …/cron-env gibt mehrere Zeilen aus, was nicht funktioniert. Versuche einfach auszuführen /usr/bin/env -i $(cat cron-env) echo $PATH im Terminal gibt es die Umgebung buchstäblich aus, anstatt sie zu benutzen. 3) Die aktuelle Umgebung leckt in die emulierte Cron-Umgebung. Versuchen: export foo=leaked; run-as-cron echo $foo. - Marco
@Marco Funktioniert in bash, was ich verwende, da es eine besser definierte Umgebung als sh ist. Ich benutze alles von pdksh, ksh (mehrere Versionen), bash und dash, also bin ich mir der Unterschiede zwischen den Implementierungen von "pure" von sh sehr bewusst, selbst wenn ich sehr streng in der gemeinsamen Teilmenge der Sprachen bleibe. :-) - Max Murphy
@Marco 2. cat gibt mehrere Zeilen aus, die funktionieren, weil die Shell-Substitution sie in eine einzige Zeile zusammenfasst, mit der Sie überprüfen können echo $(cat cron-env ) | wc; Ihr Beispielbefehl, /usr/bin/env -i $(cat cron-env) echo $PATH, Ersatzstoffe $PATH von der rufenden Hülle; stattdessen sollte es eine Subshell aufrufen, die in der Sub-Umgebung, z. /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH'. 3. Sie haben den gleichen Fehler gemacht, indem Sie erneut die aufrufende Shell und nicht die untergeordnete Umgebung ersetzt haben - John Freeman


Ich präsentiere eine Lösung basierend auf Pistos Antwort, aber ohne die Fehler.

  • Fügen Sie der Crontab die folgende Zeile hinzu, z. verwenden crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • Erstellen Sie ein Shell-Skript, das einen Befehl in derselben Umgebung ausführt, in der Cron-Jobs ausgeführt werden:

    #!/bin/sh
    
    . "$1"
    exec /usr/bin/env -i "$SHELL" -c ". $1; $2"
    

Benutzen:

run-as-cron <cron-environment> <command>

z.B.

run-as-cron /home/username/cron-env 'echo $PATH'

Beachten Sie, dass das zweite Argument in Anführungszeichen gesetzt werden muss, wenn ein Argument benötigt wird. Die erste Zeile des Skripts lädt eine POSIX-Shell als Interpreter. Die zweite Zeile enthält die Cron-Umgebungsdatei. Dies ist erforderlich, um die richtige Shell zu laden, die in der Umgebungsvariablen gespeichert ist SHELL. Dann lädt es eine leere Umgebung (um zu verhindern, dass Umgebungsvariablen in die neue Shell eindringen), startet dieselbe Shell, die für Cronjobs verwendet wird, und lädt die Cron-Umgebungsvariablen. Abschließend wird der Befehl ausgeführt.


34
2017-09-24 18:46



Dies half mir, meinen Rubin-bezogenen Sphinx-Ladefehler zu reproduzieren. - cweiske
Ich habe die Option @reboot cron verwendet, um die cron-env-Datei zu schreiben. Sie können es dann in der Crontab lassen und es wird nur neu geschrieben, wenn das System gestartet wird. Es macht es ein wenig einfacher, da Sie keine Zeilen hinzufügen / entfernen müssen. - Michael Barton


Da crontab den Job nicht macht, wirst du den Inhalt manipulieren:

crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done

Was es macht :

  • listet Crontab-Jobs auf
  • Entferne Kommentarzeilen
  • Entfernen Sie die Crontab-Konfiguration
  • dann starte sie nacheinander

14
2017-08-19 19:45



Das tut es nicht unbedingt in der gleichen Umgebung, wie Cron es tun würde, und ich dachte, er wollte nur einen von ihnen testen. - Falcon Momot
richtig, ich habe mich geirrt ... es laufen nur die jobs aber nicht wie cron das machen würde! - Django Janny
immer noch eine tolle Lösung +1 - Eric Uldall


Standardmäßig mit den meisten Standard-Cron-Daemonen, die ich gesehen habe, gibt es einfach keine Möglichkeit, Cron zu sagen, dass er genau hier laufen soll. Wenn Sie anacron verwenden, kann es möglich sein, dass ich eine separate Instanz im Vordergrund ausführen möchte.

Wenn Ihre Skripts nicht ordnungsgemäß ausgeführt werden, berücksichtigen Sie dies nicht

  • Das Skript wird als bestimmter Benutzer ausgeführt
  • Cron hat eine eingeschränkte Umgebung (die offensichtlichste Manifestation davon ist ein anderer Pfad).

Von crontab (5):

Mehrere Umgebungsvariablen sind festgelegt   automatisch von der Cron (8)   Daemon. SHELL ist auf / bin / sh und eingestellt   LOGNAME und HOME werden von der   / etc / passwd Zeile der Crontab   Inhaber. PATH ist auf "/ usr / bin: / bin" eingestellt.   HOME, SHELL und PATH können sein   überschrieben durch Einstellungen in der   Crontab; LOGNAME ist der Benutzer, der die   Job läuft ab und kann nicht sein   geändert.

Im Allgemeinen ist PATH das größte Problem. Sie müssen also:

  • Legen Sie explizit den PATH innerhalb des Skripts beim Testen auf / usr / bin: / bin fest. Sie können dies in bash mit tun export PATH = "/ usr / bin: / bin"
  • Stellen Sie explizit den gewünschten PATH am oberen Rand der crontab ein. z.B. PATH = "/ usr / bin: / bin: / usr / lokal / bin: / usr / sbin: / sbin"

Wenn Sie das Skript als einen anderen Benutzer ohne eine Shell ausführen müssen (z. B. www-data), verwenden Sie sudo:

sudo -u www-data /path/to/crontab-script.sh

Das erste, was Sie vor dem ganzen testen müssen, ist natürlich, dass Ihr Skript tatsächlich das tut, was es von der Kommandozeile aus tun soll. Wenn Sie es nicht über die Befehlszeile ausführen können, funktioniert es natürlich nicht mit cron.


5
2017-11-18 14:27



Danke für die gründliche Antwort. Ich bin mir der beiden Probleme bewusst, dass ich als bestimmter Benutzer und mit einer bestimmten Umgebung ausgeführt werde. Als solche habe ich meine eigene Antwort formuliert, die ich jetzt posten werde ... - Pistos
Escape-Zeichen sind ein berechtigter Grund dafür, dass der Job nicht ausgeführt wird - Joe Phillips


Nun, der Benutzer ist der selbe wie der, den Sie in den Crontab-Eintrag setzen (oder wessen Crontab Sie abwechselnd einsetzen), also ist das ein Kinderspiel. crontab(5) sollte Ihnen die Liste der Umgebungsvariablen geben, es gibt nur wenige.


1
2017-11-18 14:04



Mit anderen Worten, Sie sagen, dass es keine Möglichkeit gibt, es zu tun? Nur "nahe genug" Workarounds? - Pistos
Nein, ich sage, dass Sie es tun können, indem Sie die Informationen verwenden, die ich in meiner Antwort angegeben habe. - womble♦


In den meisten Crontabs wie z.B. vixie-cron Sie können Variablen in der crontab selbst so platzieren und dann / usr / bin / env verwenden, um zu prüfen, ob es funktioniert hat. Auf diese Weise können Sie Ihr Skript in crontab arbeiten lassen, sobald Sie herausgefunden haben, was mit dem Run-as-Cron-Skript falsch ist.

SHELL=/bin/bash
LANG=en
FASEL=BLA

* * * * *   /usr/bin/env > /home/username/cron-env

1
2017-10-27 06:52





Marcos Skript funktionierte aus irgendeinem Grund nicht für mich. Ich hatte keine Zeit zu debuggen, also schrieb ich ein Python-Skript, das das Gleiche macht. Es ist länger, aber: Erstens, es funktioniert für mich, und zweitens finde ich es leichter zu verstehen. Ändern Sie "/ tmp / cron-env" dahin, wo Sie Ihre Umgebung gespeichert haben. Hier ist es:

#!/usr/bin/env python
from __future__ import division, print_function

import sys
import os

def main():
    if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
        print("Usage: {} CMD\n"
              "Run a command as cron would. Note that CMD must be quoted to be only one argument."
              .format(sys.argv[0]))
        sys.exit(1)
    _me, cmd = sys.argv
    env = dict(line.strip().split('=', 1) for line in open('/tmp/cron-env'))
    sh = env['SHELL']
    os.execvpe(sh, [sh, '-c', cmd], env)

if __name__ == '__main__':
    main()

1
2017-12-24 08:48





Marcos Lösung funktionierte nicht für mich, aber Noam's Python-Skript funktionierte. Hier ist eine kleine Änderung an Marcos Skript, die es für mich funktionierte:

#!/bin/sh
. "$1"
exec /usr/bin/env -i "$SHELL" -c "set -a;. $1; $2"

Das hinzugefügt set -a Export von Variablen, die im Skript $ 1 definiert sind und für den Befehl $ 2 verfügbar gemacht wurden

p.s. Noam's Python funktionierte, weil es die Umgebung in den Kindprozess exportierte.


1
2018-05-11 05:05





Ich habe nie einen Weg gefunden, Cron-Jobs manuell auszuführen, aber diese write-up schlägt vor, die gleiche Umgebung einzustellen wie der Cronjob und würde das Skript manuell ausführen.


0
2017-11-18 14:07



Was schlagen Sie vor, was das OP wissen möchte? - womble♦
Aus diesem Grund habe ich den Link zu der Beschreibung hinzugefügt, die beschreibt, wie es gemacht wird. Ich hielt es nicht für nötig, hier alles zu kopieren und einzufügen. - oneodd1


Sie können den Job programmieren, um die nächste Minute zu beginnen :)


0
2017-09-23 13:52



59 Sekunden sind viel Zeit. - Stéphane Bruckert
Das OP erwähnte diese Möglichkeit in der Frage: "Gibt es eine Möglichkeit, dies zu tun? 60 Sekunden warten, um Skriptänderungen zu testen, ist nicht praktikabel." - Andrew Grimm
59 Sekunden sind wahrscheinlich weniger, als es nötig wäre, andere vorgeschlagene (und nicht garantierte) Lösungen auszuwählen und umzusetzen. Wenn ich solche Mängel sehe, frage ich mich, wie Linux zu einem solchen de-facto-Standard-Server-Betriebssystem wurde. Würde kein ernsthafter Systemadministrator ihre Jobs testen wollen? - Rolf