Wo kann ich Umgebungsvariablen festlegen, die crontab verwendet?

266

Ich habe jede Stunde eine Crontab. Der Benutzer, der es ausführt, weist Umgebungsvariablen auf, die .bash_profilefunktionieren, wenn der Benutzer den Job vom Terminal aus ausführt. Diese werden jedoch offensichtlich nicht von crontab erfasst, wenn er ausgeführt wird.

Ich habe versucht Einstellung sie in .profileund .bashrcaber sie scheinen immer noch nicht zu abgeholt. Weiß jemand, wo ich Umgebungsvariablen ablegen kann, die Crontab aufnehmen kann?

James
quelle

Antworten:

88

Lassen Sie 'cron' ein Shell-Skript ausführen, das die Umgebung festlegt, bevor Sie den Befehl ausführen.

Immer.

#   @(#)$Id: crontab,v 4.2 2007/09/17 02:41:00 jleffler Exp $
#   Crontab file for Home Directory for Jonathan Leffler (JL)
#-----------------------------------------------------------------------------
#Min     Hour    Day     Month   Weekday Command
#-----------------------------------------------------------------------------
0        *       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/hourly
1        1       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/daily
23       1       *       *       1-5     /usr/bin/ksh /work1/jleffler/bin/Cron/weekday
2        3       *       *       0       /usr/bin/ksh /work1/jleffler/bin/Cron/weekly
21       3       1       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/monthly

Die Skripte in ~ / bin / Cron sind alle Links zu einem einzigen Skript, 'runcron', das wie folgt aussieht:

:       "$Id: runcron.sh,v 2.1 2001/02/27 00:53:22 jleffler Exp $"
#
#       Commands to be performed by Cron (no debugging options)

#       Set environment -- not done by cron (usually switches HOME)
. $HOME/.cronfile

base=`basename $0`
cmd=${REAL_HOME:-/real/home}/bin/$base

if [ ! -x $cmd ]
then cmd=${HOME}/bin/$base
fi

exec $cmd ${@:+"$@"}

(Geschrieben mit einem älteren Codierungsstandard - heutzutage würde ich am Anfang ein Shebang '#!' Verwenden.)

Das '~ / .cronfile' ist eine Variation meines Profils zur Verwendung durch cron - streng nicht interaktiv und kein Echo, um laut zu sein. Sie können stattdessen die Ausführung des .profile usw. veranlassen. (Das REAL_HOME-Zeug ist ein Artefakt meiner Umgebung - Sie können so tun, als wäre es dasselbe wie $ HOME.)

Dieser Code liest also die entsprechende Umgebung und führt dann die Nicht-Cron-Version des Befehls aus meinem Home-Verzeichnis aus. So sieht beispielsweise mein Befehl 'Wochentag' wie folgt aus:

:       "@(#)$Id: weekday.sh,v 1.10 2007/09/17 02:42:03 jleffler Exp $"
#
#       Commands to be done each weekday

# Update ICSCOPE
n.updics

Der Befehl 'täglich' ist einfacher:

:       "@(#)$Id: daily.sh,v 1.5 1997/06/02 22:04:21 johnl Exp $"
#
#       Commands to be done daily

# Nothing -- most things are done on weekdays only

exit 0
Jonathan Leffler
quelle
246

Sie können Umgebungsvariablen in der Crontab selbst definieren, wenn Sie crontab -eüber die Befehlszeile ausgeführt werden.

LANG=nb_NO.UTF-8
LC_ALL=nb_NO.UTF-8
# m h  dom mon dow   command

* * * * * sleep 5s && echo "yo"

Diese Funktion ist nur für bestimmte Implementierungen von cron verfügbar. Ubuntu und Debian verwenden derzeit vixie-cron , mit dem diese in der crontab-Datei (auch GNU mcron ) deklariert werden können .

Archlinux und RedHat verwenden cronie, das das Deklarieren von Umgebungsvariablen nicht zulässt und Syntaxfehler in cron.log auslöst. Problemumgehung kann pro Eintrag durchgeführt werden:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
carestad
quelle
58
Beachten Sie, dass Sie die Variablensubstitution nicht wie in der Shell verwenden können. Daher wird eine Deklaration wie PATH = / usr / local / bin: $ PATH wörtlich interpretiert.
Zac
8
Ich konnte die Umgebungsvariablen in der Crontab selbst unter RedHat 4.4.7-3 und cronie-1.4.4-15.el6.x86_64
Bruno Lange
7
Sie müssen Variablen nicht wirklich exportieren, wenn die Variablen nur innerhalb des Befehls verwendet werden. Stellen Sie sie einfach vor Ihren Befehl. "* * * * * Schlaf 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran
@BrunoLange Könntest du pelase teilen, wie hast du es geschafft, sie einzurichten?
Newskooler
145

Ich habe noch eine Lösung für dieses Problem:

0 5 * * * . $HOME/.profile; /path/to/command/to/run

In diesem Fall werden alle in Ihrer $HOME/.profileDatei definierten Umgebungsvariablen ausgewählt .

Natürlich $HOMEist auch nicht festgelegt, Sie müssen es durch den vollständigen Pfad Ihres ersetzen $HOME.

Vishal
quelle
Dies funktionierte für mich, nachdem ich viel Mühe hatte, die Antwort zu finden, danke!
Vladimir Montealegre
5
Dies funktionierte nicht für mich, bis mir klar wurde, dass ich diesen Zeitraum vor $ HOME ausgelassen hatte. Was genau macht diese Zeit?
Flymike
9
Der Zeitraum entspricht dem Befehl "source": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W
@PeterLee hat irgendetwas Erwähntes für Sie funktioniert? Ich habe dies geschrieben, da die oben genannten Lösungen für mich nicht effektiv waren. Wenn die oben genannte Lösung nicht funktioniert, muss ich einige Nachforschungen anstellen, um den Grund zu finden. ;-)
Vishal
3
@ Vishal Eigentlich funktioniert es jetzt bei mir. Ich habe es versucht source ~/.bashrc, und es stellt sich heraus, dass meine .bashrcDatei in irgendeiner Weise mit dem Cron-Job in Konflikt steht. Wenn ich eine sehr einfache .env_setup_rcDatei mit nur einer Zeile verwende export MY_ENV_VAR=my_env_val:, funktioniert es tatsächlich. Siehe meinen Beitrag: stackoverflow.com/questions/15557777/…
Peter Lee
62

Das Einstellen von vars hat /etc/environmentauch in Ubuntu für mich funktioniert. Ab 12.04 werden Variablen in /etc/environmentfür cron geladen.

Augusto Destrero
quelle
11
Beste Antwort, einfach ausführen env >> /etc/environmentund alle aktuellen Umgebungsvariablen sind jetzt in den CRON-Jobs verfügbar.
Savageman
6
Das funktioniert gut für mich. vor allem, weil ich auf einen Docker-Container stoße, daher interessieren mich "systemweite" Implikationen nicht sonderlich.
Lucas Pottersky
14
@Savageman, das ist wie das Töten von Fliegen mit Fusionsbomben, auch die Einsätze für unerwartetes Verhalten sind extrem hoch.
Fran Marzoa
2
Seien Sie vorsichtig: env >> /etc/environmentWird fehlschlagen, wenn in einer der Umgebungsvariablen ein Hash-Zeichen vorhanden ist. Es fiel mir am schwersten, meine Anwendung zu beheben. Es stellte sich heraus, dass es sich um ein Passwort mit '#' handelte, das bei diesem Schritt abgeschnitten wurde.
Asac
3
Dies sollte die gewählte Antwort sein. Ich weiß nicht, warum Leute Dinge mit den anderen Antworten oder mit diesem Zeug über env >> / etc / environment komplizieren. Blinken Sie einfach gut, bearbeiten Sie etc / environment, wenn Sie möchten, dass diese env-Variablen universell verfügbar sind: Meine Experimente scheinen zu bestätigen, dass Exportanweisungen für env-Variablen in / etc / environment sowohl für crontab als auch für Benutzer verfügbar sind. DAS PROBLEM: Nochmals aus meinen Experimenten: Es scheint, dass diese Umgebungsvariablen in Crontab selbst NICHT ERWEITERT sind! ... dh sie werden nur in den aufgerufenen Skripten erweitert!
Mike Nagetier
39

Wenn Sie die Skripte starten, die Sie über cron ausführen, mit:

#!/bin/bash -l

Sie sollten Ihre ~/.bash_profileUmgebungsvariablen erfassen

breizhmg
quelle
4
Diese Antwort sollte mehr positive Stimmen erhalten und einfach die ausgewählte Antwort sein: Sehr einfach und elegant und vermeidet unzählige Kludges, die ein Springen über das gesamte System erfordern würden.
JakeGould
Ich mag diese Antwort +1. Könnte / sollte dies verwendet werden, wenn rootCrontab ausgeführt wird? Es gibt keinen /home/rootOrdner auf meinem System und daher sehe ich nicht, wie dies mit rootCrontab funktionieren würde . Ideen?
Seamus
Im Skript selbst. Was Sie dann normal mit cron laufen lassen.
Breizhmg
@ Jim siehe dieses Beispiel , klassische ausführbare Datei (chmod 777) verwenden #!/bin/bash. Die Magie hier ist hinzuzufügen-l
Peter Krauss
22

Das @ carestad-Beispiel zu erweitern, das ich einfacher finde, besteht darin, das Skript mit cron auszuführen und die Umgebung im Skript zu haben.

In der crontab -e Datei:

SHELL=/bin/bash

*/1 * * * * $HOME/cron_job.sh

In der Datei cron_job.sh:

#!/bin/bash
source $HOME/.bash_profile
some_other_cmd

Jeder Befehl nach der Quelle von .bash_profile hat Ihre Umgebung so, als ob Sie angemeldet wären.

Robert Brisita
quelle
16

Für mich musste ich die Umgebungsvariable für eine PHP-Anwendung einstellen. Ich habe es wieder aufgenommen, indem ich den folgenden Code zu meiner Crontab hinzugefügt habe.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

* * * * * /home/deploy/my_app/cron/cron.doSomethingWonderful.php

und in doSomethingWonderful.php konnte ich den Umgebungswert erhalten mit:

<?php     
echo $_SERVER['ENVIRONMENT_VAR']; # => "production"

Ich hoffe das hilft!

Karlingen
quelle
Das hat bei mir nicht funktioniert. Die Umgebungsvariable war in dem Skript, das in der Crontab aufgerufen wurde, nicht verfügbar.
Nikhil
12

Was auch immer Sie eingestellt haben crontab wird in den Cronjobs sowohl direkt als auch unter Verwendung der Variablen in den Skripten verfügbar sein.

Verwenden Sie sie in der Definition des Cronjobs

Sie können crontabso konfigurieren , dass Variablen festgelegt werden, die dann vom Cronjob verwendet werden können:

$ crontab -l
myvar="hi man"
* * * * * echo "$myvar. date is $(date)" >> /tmp/hello

Jetzt /tmp/hellozeigt die Datei Dinge wie:

$ cat /tmp/hello 
hi man. date is Thu May 12 12:10:01 CEST 2016
hi man. date is Thu May 12 12:11:01 CEST 2016

Verwenden Sie sie in dem von cronjob ausgeführten Skript

Sie können crontabso konfigurieren , dass Variablen festgelegt werden, die dann von den Skripten verwendet werden können:

$ crontab -l
myvar="hi man"
* * * * * /bin/bash /tmp/myscript.sh

Und sagen Sie, das Skript /tmp/myscript.shist wie folgt:

echo "Now is $(date). myvar=$myvar" >> /tmp/myoutput.res

Es wird eine Datei generiert, die Folgendes /tmp/myoutput.reszeigt:

$ cat /tmp/myoutput.res
Now is Thu May 12 12:07:01 CEST 2016. myvar=hi man
Now is Thu May 12 12:08:01 CEST 2016. myvar=hi man
...
fedorqui 'SO hör auf zu schaden'
quelle
7

Das Erweitern von @Robert Brisita wurde gerade erweitert. Wenn Sie nicht alle Variablen des Profils im Skript einrichten möchten, können Sie die zu exportierenden Variablen oben im Skript auswählen

In der crontab -e Datei:

SHELL=/bin/bash

*/1 * * * * /Path/to/script/script.sh

In script.sh

#!/bin/bash
export JAVA_HOME=/path/to/jdk

some-other-command
Marcos Pousada
quelle
7

Anstatt

0  *  *  *  *  sh /my/script.sh

Verwenden Sie bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
quelle
1
Warum hat dies, anstatt nur die Bash-Deklaration oben in der Datei zu haben, -lFolgendes : #!/bin/bash -l? Diese andere Antwort ist einfach und elegant.
JakeGould
1
Was ist, wenn ich ein Perl / Python / Ruby-Skript ausführen muss, das nicht Bash ist? Ich kann #! / Bin / bash -l nicht am Anfang eines Python-Skripts hinzufügen.
Ilya Kharlamov
"Was ist, wenn ich ein Perl / Python / Ruby-Skript ausführen muss, das nicht Bash ist?" Meinetwegen. Aber meiner Meinung nach könnten Sie einen einfachen Bash-Skript-Wrapper schreiben, der dann das Python-Skript aufruft. Ähnliches mache ich für PHP-Skripte. Der Grund dafür ist, dass das Sperren von Prozessen in Bash so viel besser und zuverlässiger ist, aber Bash-Scripting bereitet immer noch Kopfschmerzen. Also habe ich Sachen in PHP für die komplexen Sachen geschrieben und Bash den Rest erledigen lassen.
JakeGould
3

Ich verwende es Oh-my-zshin meinem MacBook, also habe ich viele Dinge versucht, um die Crontab-Task .zshrczum Laufen zu bringen, aber schließlich stellte meine Lösung das vor dem Befehl auszuführende vor.

*/30 * * * * . $HOME/.zshrc; node /path/for/my_script.js

Diese Aufgabe wird alle 30 Minuten ausgeführt und verwendet .zshrc Profil, um meinen Knotenbefehl auszuführen.

Vergessen Sie nicht, den Punkt vor dem $HOMEvar zu verwenden.

Stiakov
quelle
2

Eine andere Möglichkeit - inspiriert von dieser Antwort -, Variablen zu "injizieren", ist die folgende (Beispiel fcron):

%daily 00 12 \
    set -a; \
    . /path/to/file/containing/vars; \
    set +a; \
    /path/to/script/using/vars

Von help set:

-a Markiert Variablen, die für den Export geändert oder erstellt wurden.

Wenn Sie + anstelle von - verwenden, werden diese Flags deaktiviert.

Also alles dazwischen set -und set +wird exportiert envund ist dann für andere Skripte usw. verfügbar. Ohne setdie Variablen zu verwenden, werden sie bezogen, leben aber inset nur in.

Abgesehen davon ist es auch nützlich, Variablen zu übergeben, wenn für ein Programm ein Nicht-Root-Konto ausgeführt werden muss, Sie jedoch einige Variablen in der Umgebung dieses anderen Benutzers benötigen. Unten finden Sie ein Beispiel für die Übergabe von nullmailer-Variablen zum Formatieren des E-Mail-Headers:

su -s /bin/bash -c "set -a; \
                    . /path/to/nullmailer-vars; \
                    set +a; \
                    /usr/sbin/logcheck" logcheck
Saucier
quelle
2

Ich habe die meisten der bereitgestellten Lösungen ausprobiert, aber zunächst hat nichts funktioniert. Es stellt sich jedoch heraus, dass es nicht die Lösungen waren, die nicht funktionierten. Anscheinend ~/.bashrcbeginnt meine Datei mit dem folgenden Codeblock:

case $- in
    *i*) ;;
    *) return;;
esac

Dies ist im Grunde genommen eine case statementÜberprüfung der aktuellen Optionen in der aktuellen Shell, um festzustellen, ob die Shell interaktiv ausgeführt wird. Wenn die Shell zufällig interaktiv ausgeführt wird, wird mit der Beschaffung der ~/.bashrcDatei fortgefahren . In einer von aufgerufenen Shell enthält crondie $-Variable jedoch nicht den iWert, der auf Interaktivität hinweist. Daher wird die ~/.bashrcDatei nie vollständig bezogen. Infolgedessen wurden die Umgebungsvariablen nie festgelegt. Wenn dies Ihr Problem ist, können Sie den Codeblock wie folgt auskommentieren und es erneut versuchen:

# case $- in
#     *i*) ;;
#     *) return;;
# esac

Ich hoffe, das wird nützlich

Abdou
quelle
0

Sie können Ihrem Befehl auch voranstellen env, um Umgebungsvariablen wie folgt einzufügen :

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
quelle