Ich habe einen Cron-Job, der jeden Tag ausgeführt werden soll. Gibt es außer der Änderung des Zeitplans eine andere Möglichkeit, den Befehl jetzt sofort zu testen, um zu sehen, ob er wie vorgesehen funktioniert?
BEARBEITEN: (aus den Kommentaren) Ich weiß, dass der Befehl einwandfrei funktioniert, wenn ich ihn in der Shell (meiner Shell) eingebe, aber ich möchte wissen, ob er richtig funktioniert, wenn er mit Cron ausgeführt wird. Er könnte durch ENV- oder Shell-spezifische Dinge (~ Erweiterung) oder Eigentums- und Berechtigungsdinge oder … beeinflusst werden.
Antwort1
Sie können die Ausführung von Crontab mit dem folgenden Befehl erzwingen:
run-parts /etc/cron.daily
Antwort2
Sie können die Cron-Benutzerumgebung simulieren, wie in„Einen Cron-Job manuell und sofort ausführen“. Auf diese Weise können Sie testen, ob der Job funktioniert, wenn er als Cron-Benutzer ausgeführt wird.
Auszug aus Link:
Schritt 1: Ich habe diese Zeile vorübergehend in die Crontab des Benutzers eingefügt:
* * * * * /usr/bin/env > /home/username/tmp/cron-env
und habe es dann herausgenommen, nachdem die Datei geschrieben war.
Schritt 2: Ich habe mir ein kleines, als Cron ausführbares Bash-Skript erstellt, das Folgendes enthält:
#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"
Als der betroffene Benutzer konnte ich dann
run-as-cron /the/problematic/script --with arguments --and parameters
Antwort3
Soweit ich weiß, gibt es keine Möglichkeit, das direkt zu tun, da Cron einen speziellen Zweck hat – das Ausführen von Zeitplanbefehlen zu einer bestimmten Zeit. Am besten ist es also, entweder manuell einen (temporären) Crontab-Eintrag zu erstellen oder ein Skript zu schreiben, das die Umgebung entfernt und zurücksetzt.
Erklärung zu „entfernt und setzt die Umgebung zurück“:
Sie könnten ein Wrapper-Skript starten env -i
(das die Umgebung entfernt), das eine gespeicherte Umgebung als Quelle verwendet (wobei Sie darauf achten, alle Variablen zu exportieren, möglicherweise indem Sie sie set -a
zuerst festlegen), bevor Sie Ihr Skript starten.
Die gespeicherte Umgebung wäre die Standardumgebung eines Cron-Jobs, der durch Ausführen als Cron-Job env
(oder declare -p
je nachdem, welche Shell Ihre Cron-Jobs verwenden) und Speichern seiner Ausgabe aufgezeichnet wird.
Antwort4
Nachdem ich selbst Cron-Jobs debuggen musste, habe ich das folgende Skript geschrieben. Es versucht, vor dem Ausführen eines Befehls genau dieselben Bedingungen wie Cron zu simulieren (das schließt eine geänderte Umgebung ein, hat aber auch mit nicht interaktiven Shells, keinem angeschlossenen Terminal usw. zu tun).
Rufen Sie es mit Ihrem Befehl/Skript als Argument auf, und Sie haben eine sofortige und schmerzlose Möglichkeit, Ihren Cron-Job zu debuggen. Es wird auch auf GitHub gehostet (und möglicherweise aktualisiert):run-as-cron.sh
:
#!/bin/bash
# Run as if it was called from cron, that is to say:
# * with a modified environment
# * with a specific shell, which may or may not be bash
# * without an attached input terminal
# * in a non-interactive shell
function usage(){
echo "$0 - Run a script or a command as it would be in a cron job," \
"then display its output"
echo "Usage:"
echo " $0 [command | script]"
}
if [ "$1" == "-h" -o "$1" == "--help" ]; then
usage
exit 0
fi
if [ $(whoami) != "root" ]; then
echo "Only root is supported at the moment"
exit 1
fi
# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
echo "Unable to find $cron_env"
echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
exit 0
fi
# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
env_string="${env_string} $envi "
done
cmd_string=""
for arg in "$@"; do
cmd_string="${cmd_string} \"${arg}\" "
done
# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"
# Let's redirect the output into files
# and provide /dev/null as input
# (so that the command is executed without an open terminal
# on any standard file descriptor)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" > "$so" 2> "$se" < /dev/null
echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"