Wie kann ich einen Cron-Befehl mit vorhandenen Umgebungsvariablen ausführen?

114

Wie kann ich einen Cron-Befehl mit vorhandenen Umgebungsvariablen ausführen?

Wenn ich an einer Shell-Eingabeaufforderung bin, kann echo $ORACLE_HOMEich einen Pfad eingeben und abrufen. Dies ist eine meiner Umgebungsvariablen, die in my gesetzt wird ~/.profile. Es scheint jedoch, dass von ~/.profileCron-Skripten keine geladen werden und meine Skripten fehlschlagen, weil die $ORACLE_HOMEVariable nicht gesetzt ist.

In dieser Frage erwähnt der Autor das Erstellen eines ~/.cronfileProfils, das Variablen für cron einrichtet, und führt dann eine Problemumgehung durch, um alle seine cron-Befehle in Skripten zu laden, die er in seinem ~/CronVerzeichnis aufbewahrt. Eine Datei ~/.cronfileklingt nach einer guten Idee, aber der Rest der Antwort scheint etwas umständlich zu sein, und ich hatte gehofft, jemand könnte mir einen einfacheren Weg nennen, um das gleiche Ergebnis zu erzielen.

Ich nehme an, zu Beginn meiner Skripte könnte ich so etwas hinzufügen, source ~/.profileaber das scheint so, als könnte es überflüssig sein.

Wie kann ich meine Cron-Skripte dazu bringen, die Variablen aus meinem Interactive-Shell-Profil zu laden?

cwd
quelle
Wie wird das Hinzufügen source ~/.profilezu einem Programm überflüssig? Programme erben ihre Umgebung vom aufrufenden Programm. Wenn dieses aufrufende Programm nicht Ihre Shell ist, wie erhält dann das untergeordnete Programm die gewünschte Umgebung?
Arcege
Ich habe hier bereits meine Antwort auf eine ähnliche Frage geschrieben . Es wird einfach verwendet, su -lum eine normale Anmeldeumgebung einzurichten, die den $ PATH für den Root-Benutzer oder einen anderen bestimmten Benutzer enthält.
Tasket

Antworten:

141

Fügen Sie in der Crontab, bevor Sie befehlen, hinzu . $HOME/.profile. Zum Beispiel:

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

Cronweiß nichts über deine Muschel; Es wird vom System gestartet, daher ist die Umgebung minimal. Wenn Sie etwas wollen, müssen Sie das selbst mitbringen.

Arcege
quelle
14
Was macht das .vor dem Drehbuch? (nicht sicher, wie ich das machen würde man). Warum ist das anders als source?
KWD
25
Der .Befehl ist der ursprüngliche Befehl für source. Sie sind innerhalb der Shell gleichwertig und etwas einfacher zu tippen, insbesondere innerhalb einer Crontab. Für weitere Informationen, geben Sie erhalten help .oder für die Suche ^SHELL BUILTIN COMMANDSnach in der Manpage bashoder an der Spitze des man zshbuiltins . Running Typs .` werden Ihnen sagen , dass der Befehl ein builtin ist.
Arcege
9
Je nach Linux - Distributionen können Sie ändern müssen .profiledurch .bash_profile. Überprüfen Sie, welche .profileDatei im Ausgangsverzeichnis des Benutzers vorhanden ist.
Frosty Z
@Arcege Das funktioniert bei mir nicht (Fedora Core 21), und ich nehme an, das liegt daran, dass der Shell-Level wieder abfällt. Stattdessen funktioniert es, wenn Sie es als Quelle angeben.
Richard T
3
Wenn es nicht funktioniert, liegt es wahrscheinlich daran, dass die SHELL für das Cron-Skript nicht auf bash eingestellt ist und daher nicht auf die erwartete Weise ausgeführt wird.
Daniel Farrell
40

Eine andere Möglichkeit, die 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 cron_job.sh Datei:

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

Bei jedem Befehl nach der Quelle von .bash_profile ist Ihre Umgebung so, als ob Sie angemeldet wären.

Robert Brisita
quelle
5
Bei der Ausführung auf einem AWS Linux AMI ist mir nicht einmal aufgefallen, dass cron nicht /bin/bashals Shell verwendet wird. Ich habe mich immer wieder gefragt, warum Dinge wie cd /path/to/project; source .varsfunktionieren, wenn ich sie manuell eingetippt habe, aber File not foundwenn sie in einem Cronjob enthalten sind, versagen sie ( ). Die Schlüsselzeile für mich war die Einstellung SHELL=/bin/bash, dass ich in jedem Cronjob vertraute Bash-Befehle verwenden konnte. /bin/sh/(die Standard-Cron-Shell anscheinend) ist sehr einschränkend.
Hartley Brody
Es ist schade, dass Sie keine Umgebungsdateien am oberen Rand des Cron angeben können, so wie Sie einzelne Umgebungsvariablen angeben können. Systemd hat eine EnvironmentFileServiceeinheit. Schade, dass cron so etwas nicht hat.
radtek
Sie FORCIEREN, dass alle Skripte / bin / bash in allen crontab verwenden, was keine gute Idee ist, auch was Ihre cron-Zeile betrifft: * / 1 * * * * $ HOME / cron_job.sh… * / 1 ist gut für WAS ?!? Ein Stern bedeutet , dass es auf jede Minute / 1 Mittel ausgeführt werden jede Minute ausgeführt werden, als Antwort in einem Smart - Community ist dies eine böse Sünde, jetzt glaube ich Ihnen sehr verwirrt sind das Beste zu sagen ... sorry
THESorcerer
1
Dies nennt man ein Beispiel. Passen Sie sich Ihren Bedürfnissen an oder verwenden Sie es überhaupt nicht. Verschiedene Schläge für verschiedene Leute.
Robert Brisita
4
Wenn $SHELLja /bin/sh, ist der sourceBefehl nicht vorhanden. Verwenden Sie .stattdessen.
Melle
18

Eine andere Möglichkeit, die ich einfacher finde, ist, das Skript mit cron auszuführen und bash anzuweisen, sich anzumelden (daher /etc/profile.d/...Umgebungsdefinitionen zu verwenden).

In der crontab -eDatei:

*/1 * * * * bash -l -c './cron_job.sh'
*/1 * * * * bash -l -c 'php -f ./cron_job.php'

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

Artistan
quelle
10

Schlechte Idee. In der Regel werden alle erforderlichen Umgebungsvariablen in einem Skript festgelegt, das von einem Cron-Job ausgeführt werden soll.

fpmurphy
quelle
Ich bin mit @fpmurphy einverstanden, dass es auch die gesicherte Prozessumgebung gewährleistet. Wenn Sie nur wenige Variablen aus cron setzen möchten, können Sie /usr/bin/envdie Variablen mit dem Befehl set- zen und dann als Umgebungsprozess für den cronjob fungieren.
Nikhil Mulley
daemontoolsenvdir kommt auch in den Sinn.
Sr_
6
Ich bin alles für die Sicherheit, aber vielleicht kann ich eine Datei erstellen ~/.cronvarsund diese in das Profil und auch in meine Cron-Skripte aufnehmen. Ich möchte Umgebungsvariablen in den Skripten, die ich ausführe, nicht hart codieren, da es nicht einfach ist, fest codierte Pfade in jeder Datei zu verwalten, wenn Pfade geändert werden. Anscheinend würde dies einen zentralen Ort für die benötigten Variablen ermöglichen und verhindern, dass andere Variablen geladen werden.
KWD
4

Diese Syntax hilft Ihnen auf jeden Fall. Ich verstehe die Syntax nicht, aber es funktioniert. Oracle verwendet diese Syntax, wenn Oracle Configuration Manager für Crontab bereitgestellt wird. Daher halte ich dies für eine richtige Lösung.

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters
meir
quelle
2

Ich bin kürzlich auf einen Fall gestoßen, in dem ich den gesamten Cronjob als root ausführen musste, gleichzeitig aber einen Unterbefehl als anderer Benutzer ausführen musste (was die Beschaffung der Umgebung dieses Benutzers erforderte). Ich bin mit folgendem Ansatz vorgegangen:

# m  h  dom  mon  dow  user  command
*/5  *   *    *    *   root  (sudo -i -u <the user> command-to-be-run-as-user) && command-to-be-run-as-root

Der entscheidende Teil ist das Argument -i, an sudodas übergeben wird, um den angegebenen Befehl in einer separaten Anmeldeshell auszuführen (was wiederum bedeutet, dass die Punktedateien des Benutzers bezogen werden).

PS: Beachten Sie, dass die userSpalte nur in /etc/crontabund den /etc/cron.d/*Dateien verfügbar ist .

balu
quelle
1

Die Lösung, die bei mir funktioniert hat, ist hier beschrieben .

Sie erstellen ein Wrapper-Skript, das aufruft . ~/.cronfileund dann die gewünschten Aktionen ausführt. Dieses Skript wird von cron gestartet.

In ~/.cronfilelegen Sie die Umgebung für Ihre Cronjobs fest.

Wochen
quelle
1

Ja, Sie können "bekannte Problemumgehungen" verwenden (von denen einige aufgelistet wurden). Dies ist eine andere Art zu sagen, dass jeder weiß, dass es beschissen ist, obwohl einige Leute dies als "Sicherheitsmerkmal" bezeichnen werden, weil sie mindestens so viel über dieses Versagen (ure) gestolpert haben, wie Sie es getan haben, und gerne an ihr denken würden Zeitverschwendung war nicht umsonst. Es ist das Cron-Äquivalent der QWERTZ-Tastatur.

Ich vermute, dass der ursprüngliche Grund für die Leistung war, so dass Skripte, die einmal pro Minute ausgeführt werden, nicht die Zeit zum Lesen von RC-Skripten verschwenden würden. Auch ursprünglich war cron überhaupt nicht konfigurierbar, so dass ein Standard die einzige Option war.

Es gibt keine zusätzliche Sicherheit, da cron keine einfache Konfiguration oder Methode hat, um nur die Umgebung Ihrer interaktiven Shell zu übernehmen, anstatt dass Benutzer dumme Shell-Gymnastik machen müssen. Auf einer modernen Maschine ist in der Regel kein Leistungszuwachs erkennbar, es sei denn, Sie haben jede Minute eine große Menge von Aufträgen ausgeführt.

Unix-Kultur scheitert. Meiner bescheidenen Meinung nach. :-)

Austin S.
quelle
1
"Es gibt keine zusätzliche Sicherheit." Das ist nicht wahr. Sehen Sie sich CVE-2011-1095 , CVE-2008-4304 und CVE-2010-3847 an .
Ich habe Ihre Antwort übrigens abgelehnt. Normalerweise versuche ich, die Antworten von Neulingen nicht herabzustimmen, aber die Sicherheit ist mir wichtig. Bitte verstehe den Downvote nicht falsch. Abgesehen von dem Teil über Sicherheit ist Ihre Antwort ausgezeichnet und verdient eine Aufwertung. Sie können Ihre Antwort hier bearbeiten , wenn Sie möchten.
Keiner von ihnen hat das geringste damit zu tun, dass cron eine Shell mit gesetztem interaktiven Flag verwendet. Das ist pure FUD. Leider kann ich Ihre Ablehnung nicht ablehnen. Das mag wie eine Flamme erscheinen, aber es ist sehr frustrierend, wenn die Leute ein Fahrzeug mit drei Rädern für besser halten, weil es ein Sicherheitsproblem gibt, ein viertes Rad aufzusetzen. Ist es nicht. Die Leute sind gerade ein Dreirad gefahren, so lange sie vergessen haben, dass es möglich ist, ein viertes Rad hinzuzufügen.
Austin S.
Anders ausgedrückt: Wenn einer der beabsichtigten zusätzlichen Rahmen verwendet wird, die von den anderen Antwortenden vorgeschlagen wurden, wie können sie dann nicht auch auf eines der von Ihnen erwähnten Löcher zugreifen? "* * * * * exec bash -i -c LOCALE = ......."
Austin S.
Das liest sich wie ein Scherz. Ich sehe nicht einmal, wo es die Frage überhaupt beantwortet. Selbst wenn der Sicherheitsteil entfernt würde, @EvanTeitelman, sehe ich keinen Grund, warum dies eine Aufwertung verdienen würde, da die Frage nicht beantwortet wird.
Wildcard
1

Anstatt ein Profil festzulegen, half mir das Festlegen des PATH. Einige der Befehle waren in meinen Cron-Skripten nicht verfügbar, da dies PATHanders ist.

ENVIRONMENT=prod
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Das Setzen PATHmit dem Befehlspfad hat mir geholfen. Noch besser, wenn Sie eine Vorlage verwenden und später wieder nachdenken können,

ENVIRONMENT={{ENVIRONMENT}}
PATH={{PATH}}
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Das Übergeben von Variablen an jedes Element sieht unordentlich aus.

Optimus Prime
quelle
-1

Ich legte . ~/.dbus/session-bus/*ganz oben auf meinem Wunschskript :)

Eric
quelle
1
Willkommen bei der U & L SE. Bitte erweitern Sie Ihre Antwort, damit es den Lesern zugute kommt.
Ramesh