cron ignoriert die in ".bashrc" und ".bash_profile" definierten Variablen

49

Ich habe die Variable "SHELL" in der Datei / etc / crontab definiert:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

Außerdem werden alle meine Skripte in der Datei / etc / crontab unter dem Benutzer "martin" gestartet. Jedoch /home/martin/.bash_profile (für Login - Shell) und /home/martin/.bashrc (für Nicht-Logging - Shell) enthalten einige Variablen , die im Falle von cron - Job ignoriert werden, sind aber für den Fall , habe ich in Maschine anmelden über SSH oder neue Bash-Sitzung eröffnen. Warum ignoriert cron diese Variablen? Führt cron nicht einfach "/usr/local/bin/bashmy-script.sh" mit den Berechtigungen des Benutzers "martin" aus?

Martin
quelle
2
Ubuntu - Anwender anmerken, dass Ubuntu Standard .bashrchat eine Linie , die sie stoppt die Ausführung von in nicht-interaktiven Shells.
Joeytwiddle

Antworten:

72

Sie können die gewünschte Datei oben im Skript oder zu Beginn des Jobs für den Benutzer, der den Job ausführt, als Quelle angeben. Der Befehl "source" ist ein integrierter Befehl. Sie würden dasselbe tun, wenn Sie Änderungen an diesen Dateien vornehmen würden, um die Änderungen zu laden.

* * * * * source /home/user/.bash_profile; <command>

oder

#!/bin/bash
source /home/user/.bash_profile

<commands>
gNU.be
quelle
2
Beachten Sie, dass "source" möglicherweise nicht funktioniert, wenn cron die bashShell nicht verwendet . Ich habe eine Antwort hinzugefügt, die den Fall behandelt, wenn die Shell ist sh.
Jonathan
23

Weil es keine interaktive Shell ist. Das gleiche passiert, wenn Sie einige Terminals öffnen.

Schauen Sie sich diese Frage an: Was ist die .bashrc-Datei? | Super User

Und auch bei diesem:

Was ist der Unterschied zwischen .bashrc, .bash_profile und .environment? | Paketüberfluss

Je nachdem, ob es sich bei der Verbindung um eine Anmeldeshell (oder nicht), eine interaktive Shell (oder nicht) oder beides handelt, werden verschiedene Skripte ausgelöst.

Wenn Sie bashrc machen wollen, müssen Sie diese Änderung vornehmen:

Wenn Bash nicht interaktiv gestartet wird, um beispielsweise ein Shell-Skript auszuführen, sucht es in der Umgebung nach der Variablen BASH_ENV, erweitert ihren Wert, falls sie dort angezeigt wird, und verwendet den erweiterten Wert als Namen einer Datei, die gelesen und ausgeführt werden soll . Bash verhält sich so, als ob der folgende Befehl ausgeführt wurde:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

Der Wert der PATH-Variablen wird jedoch nicht für die Suche nach dem Dateinamen verwendet.

Wie oben erwähnt, --loginversucht Bash , wenn eine nicht interaktive Shell mit dieser Option aufgerufen wird , Befehle aus den Startdateien der Anmeldeshell zu lesen und auszuführen.

Quelle: Bash-Startdateien | Bash-Referenzhandbuch | gnu.org

Dave C
quelle
Wenn wir also BASH_ENV in Cron setzen, werden cron-bash-Skripte dies ausgeben, da cron nicht interaktiv und nicht angemeldet ist.
CMCDragonkai
12

Sie können möglicherweise nicht ausgeführt werden, sourcewenn die shShell verwendet wird. Dies kann durch Hinzufügen der folgenden Zeile in Ihrer Crontab geändert werden:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Sie können auch die Umgebung angeben:

BASH_ENV="/root/.bashrc"
* * * * * <command>

oder Sie können Ihr lokales verwenden, /home/user/.bashrcwenn es ein Benutzer cron Job ist (zB crontab -e).

Beachten Sie, dass .bash_profileersetzen kann .bashrc, wenn es existiert.

Kredit: Wie man cron Oberteil ändert (sh zum heftig zu schlagen)?

Jonathan
quelle
Dies funktioniert auch gut für Acquia Cloud Scheduled-Jobs, bei denen es sich im Grunde um Cron-Jobs handelt. Sie können das gleiche tun, wie:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

Etwas anderes, das die Beschaffung Ihres .bashrcCronjobs beeinträchtigen könnte, sind Überprüfungen, die diese Datei vornimmt, um interaktive Shells zu erkennen.

Unter Ubuntu 18.04 .bashrcbeginnt die Standardeinstellung für einen Benutzer beispielsweise folgendermaßen:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

und so Sourcing wird es nichts Sinnvolles tun, da es sofort beendet wird.

François Marier
quelle
1

Sie können Bash mit der folgenden -lOption aufrufen :

* * * * * /bin/bash -l /path/to/script arg1 arg2

Die -lOption macht Bash zu einer Login- Shell. Auf diese Weise wird der Benutzer gelesen .bash_profile. Der Benutzer wird nicht gelesen, es .bashrcsei denn, es wird explizit von bezogen .bash_profile. Dies liegt daran, dass nicht interaktive Shells nicht automatisch gelesen werden .bashrc. Sie sollten jedoch keinen .bashrcCron-Job benötigen, um .bashrcnützliche Einstellungen für eine interaktive Shell vorzunehmen.

Variationen:

Wenn sich die Bash auf dem Pfad befindet, muss kein absoluter Pfad angegeben werden:

* * * * * bash -l /path/to/script arg1 arg2

Eine Optimierung wäre das Ersetzen der aktuellen Shell durch exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
quelle
1

bashverhält sich anders, egal ob es sich um eine Shell oder eine normale Programmiersprache handelt (wie perloder python).

Durch Design, die Einstellungen in ~/.bash_profile, ~/.bashrcusw. sind für die Benutzer - Set Dinge , wenn bashspielt die Rolle einer Schale (Login - Shell, interractive Shell). Denken Sie an die Umgebung, die Sie in einer xterm(interaktiven Shell) oder in sshSitzungen (Anmeldeshell) oder in Konsolen (Anmeldeshell) haben.

Andererseits bashist es auch eine leistungsstarke Programmiersprache, die über viele Skripte zum Verwalten von Diensten nachdenkt und systemdeinen anderen Arbeitsstil erfordert. Wenn ein Entwickler beispielsweise ein Systemskript oder ein bashProgramm schreibt , möchte er den Benutzer nicht ~/.bash_profileautomatisch als Quelle verwenden . Es ist ein normales Programm, keine Shell. Ein normales Programm (einschließlich bashProgramme) würde natürlich Einstellungen von der aktuellen Arbeitsumgebung (Shell) erben , diese jedoch nicht festlegen .

Wenn wir ein Programm für cronin schreiben, wird bashes zufällig in geschrieben bash. in der Tat können wir es in schreiben pythonoder perloder andere Progammierung sprach dann können wir eine Option Quellen haben bash‚s ~/.bash_profile(sprich: die Benutzer-Shell - Einstellung, die nur zufällig die gleiche Sprache Ihrer Programmiersprache sein):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

Was ist jedoch, wenn dieser bestimmte Benutzer nicht bashals Shell verwendet? Er / sie verwenden kann zsh, ksh, fishusw. Also, diese Praxis funktionieren würde, nicht wirklich , wenn Programm für die öffentliche Nutzung zu schreiben.

Sie können also Quellen ~/.bash_profileangeben, wenn Sie glauben, dass dies funktionieren wird. Aber hier geht es nicht darum, ob wir eine Datei beschaffen können, sondern darum, wie die Dinge im System funktionieren sollen: das Designkonzept . Kurz gesagt: Wir sollten bashetwas mit zwei Rollen sehen: Shell und Programmiersprache . Dann wird alles viel einfacher zu verstehen sein.

Bach Lien
quelle
0

Ich hatte das gleiche Problem beim Ausführen einer Knotenanwendung von cron, die NVM verwendet. Um die bash-Shell zum Lesen der .bashrc-Datei von cron zu veranlassen, rufen Sie einfach den Befehl bash mit der interaktiven Shell-Option `-l auf.

z.B: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Wenn dies nicht funktioniert, setzen Sie die Pfadvariable in crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "
Shyam Jos
quelle
-1

Meine Art damit umzugehen war:

1) Meine Variablen eingeben (Ende von) ~/.profile:

myVarInDotProfile="someValue"

2) Erstellen eines Bash-Skripts für meine (täglichen) Cron-Tasks ( ~/cronDaily.sh) mit meinen Befehlen und wiederholtem Sourcing von ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) Planen der Ausführung meines Skripts von crontab, bis zur täglichen Ausführung :

0 0 * * * bash ~/cronDaily.sh

Meine Variable wurde nicht ignoriert und die Befehle wurden erfolgreich ausgeführt.


Einige mögen sagen, dass eine derart intensive Beschaffung ~/.profileproblematisch ist. In meinem speziellen Fall sehe ich nicht, warum es ein Problem ist, aber ich würde empfehlen, eine dedizierte Datei dafür zu erstellen.

Im Allgemeinen gibt es vielleicht einen besseren Weg, aber genau das hat bei mir nach vielen Schmerzen funktioniert und erklärt das Prinzip, dass Sie ab Bash 4.3.46 keine Datei mehr aus diesem Quellcode beziehen können crontab.

Arcticooling
quelle