cron ignoruje zmienne zdefiniowane w „.bashrc” i „.bash_profile”

49

Zdefiniowałem zmienną „SHELL” w pliku / etc / crontab:

[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 ~]$ 

Dodatkowo, wszystkie moje skrypty w pliku / etc / crontab są uruchamiane przez użytkownika „martin”. Jednak /home/martin/.bash_profile (dla powłoki logowania) i /home/martin/.bashrc (dla powłoki nielogującej ) zawierają pewne zmienne, które są ignorowane w przypadku zadania cron, ale są używane w przypadku, gdy zaloguję się na maszynie SSH lub otwórz nową sesję bash. Dlaczego cron ignoruje te zmienne? Czy cron nie wykonuje po prostu „/ usr / local / bin / bash my-script.sh” z uprawnieniami dla użytkownika „martin”?

Jaskółka oknówka
źródło
2
Użytkownicy Ubuntu mogą zauważyć, że domyślna linia Ubuntu .bashrcma linię, która powstrzymuje ją przed uruchomieniem w nieinteraktywnych powłokach.
joeytwiddle

Odpowiedzi:

72

Możesz pobrać plik, który chcesz na górze skryptu lub na początku zadania dla użytkownika, który wykonuje zadanie. Polecenie „source” jest wbudowane. Zrobiłbyś to samo, gdybyś dokonał edycji tych plików, aby załadować zmiany.

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

lub

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

<commands>
gNU.be
źródło
2
Zauważ, że „source” może nie działać, jeśli cron nie używa bashpowłoki. Dodałem odpowiedź, która może obsłużyć skrzynkę, gdy jest to powłoka sh.
Jonathan
23

Ponieważ to nie jest interaktywna powłoka. To samo dzieje się po otwarciu niektórych terminali.

Spójrz na to pytanie: Co to jest plik .bashrc? | Super użytkownik

A także w tym:

Jaka jest różnica między .bashrc, .bash_profile i .environment? | Przepełnienie stosu

Różne skrypty są uruchamiane w zależności od tego, czy połączenie jest powłoką logowania (czy nie), powłoką interaktywną (czy nie), czy też jednymi i drugimi.

Jeśli chcesz zrobić bashrc, musisz wprowadzić tę zmianę:

Gdy Bash jest uruchamiany nieinteraktywnie, aby na przykład uruchomić skrypt powłoki, szuka w środowisku zmiennej BASH_ENV, rozszerza swoją wartość, jeśli się tam pojawia, i używa wartości rozwiniętej jako nazwy pliku do odczytu i wykonania . Bash zachowuje się tak, jakby wykonano następujące polecenie:

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

ale wartość zmiennej PATH nie jest używana do wyszukiwania nazwy pliku.

Jak wspomniano powyżej, jeśli wywoływana jest nieinteraktywna powłoka z --loginopcją, Bash próbuje odczytać i wykonać polecenia z plików startowych powłoki logowania.

Źródło: Pliki startowe Bash | Podręcznik referencyjny Bash | gnu.org

Dave C.
źródło
Więc jeśli ustawimy BASH_ENV wewnątrz Crona, skrypty cron bash będą je pozyskiwać, ponieważ cron jest nieinteraktywny i nie loguje się.
CMCDragonkai,
12

Może nie być w stanie uruchomić source, jeśli shpowłoka jest używany. Można to zmienić, dodając następujący wiersz do tabeli:

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

Możesz także określić środowisko:

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

lub możesz użyć swojego lokalnego, /home/user/.bashrcjeśli jest to zadanie cron użytkownika (np crontab -e.).

Pamiętaj, że .bash_profilemożna go zastąpić .bashrc, jeśli istnieje.

Credit: Jak zmienić powłokę crona (sh na bash)?

Jonathan
źródło
działa to również dobrze dla zadań Acquia Cloud Scheduled, które są w zasadzie zadaniami cron. Możesz zrobić to samo, na przykład:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

.bashrcInną rzeczą, która może zakłócać pozyskiwanie twoich zasobów przez cronjob, są wszelkie kontrole wykonywane przez ten plik w celu wykrycia interaktywnych powłok.

Na przykład w systemie Ubuntu 18.04 domyślna wartość .bashrcdla użytkownika zaczyna się od:

# ~/.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

a więc pozyskiwanie nie przyniesie nic pożytecznego, ponieważ natychmiast zakończy działanie.

Francois Marier
źródło
1

Możesz wywołać bash z -lopcją, jak poniżej:

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

Ta -lopcja sprawia, że ​​bash jest powłoką logowania . W ten sposób odczyta użytkownika .bash_profile. Nie będzie czytać użytkownika, .bashrcchyba że zostanie to wyraźnie pozyskane przez .bash_profile. Jest tak, ponieważ nieinteraktywne powłoki nie odczytują się automatycznie .bashrc. Ale nie powinieneś potrzebować .bashrczadania crona, ponieważ .bashrcsłuży ono do ustawiania rzeczy przydatnych dla interaktywnej powłoki.

Wariacje:

Jeśli bash jest na ŚCIEŻCE, nie ma potrzeby określania ścieżki bezwzględnej:

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

Optymalizacją byłoby zastąpienie bieżącej powłoki za pomocą exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
źródło
1

bashdziała inaczej, niezależnie od tego, czy jest to powłoka, czy zwykły język programowania (jak perllub python).

Zgodnie z projektem, ustawienia w ~/.bash_profile, ~/.bashrcitp są dla użytkowników, aby ustawić rzeczy, gdy bashodgrywa rolę powłoki (shell logowania interractive shell). Pomyśl o środowisku, które masz w xterm(powłoce interaktywnej) lub w sshsesjach (powłoka logowania) lub w konsolach (powłoka logowania).

Z drugiej strony bashjest także potężnym językiem programowania - pomyśl o wielu skryptach do zarządzania usługami systemd- który wymaga innego stylu pracy. Na przykład, gdy programista pisze skrypt systemowy lub bashprogram, nie będzie chciał ~/.bash_profileautomatycznie pozyskiwać użytkownika . Jest to normalny program, a nie powłoka. Normalny program (w tym bashprogramy) w naturalny sposób dziedziczy ustawienia z bieżącego środowiska roboczego (powłoki), ale ich nie ustawia .

Jeśli napiszemy program dla cronin bash- akurat się w nim zapisuje bash; w rzeczywistości, możemy zapisać go w pythonlub perllub inny progamming language- wtedy możemy mieć opcję źródeł bash„s ~/.bash_profile(czytaj: ustawienie muszli użytkownika, który okazuje się być tym samym języku, języku programowania):

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

Co jednak, jeśli ten konkretny użytkownik nie używa bashswojej powłoki? On / ona może używać zsh, ksh, fish, itd. Tak, że praktyka nie naprawdę działa przy pisaniu programu do użytku publicznego.

Możesz więc zdobyć źródło, ~/.bash_profilejeśli uważasz, że to zadziała. Ale tutaj nie chodzi o to, czy jesteśmy w stanie pobrać plik, chodzi o to, jak powinno działać w systemie: koncepcja projektowa . W skrócie: powinniśmy postrzegać bashjako coś mającego 2 role: powłokę i język programowania . Wtedy wszystko będzie znacznie łatwiejsze do zrozumienia.

Bach Lien
źródło
0

Miałem ten sam problem podczas uruchamiania aplikacji węzła z crona, która korzysta z NVM. Aby zrobić powłokę bash do odczytu pliku .bashrc z crona, wystarczy wywołać polecenie bash z opcją interaktywnej powłoki `-l.

na przykład: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Jeśli to nie zadziała, spróbuj ustawić zmienną ścieżki w crontab

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

Mój sposób na poradzenie sobie z tym był następujący:

1) Umieszczanie moich zmiennych w (koniec) ~/.profile:

myVarInDotProfile="someValue"

2) Tworzenie skryptu Bash dla moich (codziennych) zadań cron ( ~/cronDaily.sh) zawierających moje polecenia oraz powtarzalne pozyskiwanie ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) planowanie wykonania skryptu crontab, aby uruchamiał się codziennie:

0 0 * * * bash ~/cronDaily.sh

Moja zmienna nie została zignorowana, a polecenia uruchomiły się pomyślnie.


Niektórzy mogą powiedzieć, że takie intensywne pozyskiwanie ~/.profilejest problematyczne. W moim szczególnym przypadku nie rozumiem, dlaczego jest to problem, ale radziłbym rozważyć utworzenie dedykowanego pliku do tego celu.

Ogólnie rzecz biorąc, może być lepszy sposób na to, ale to działało dla mnie po dużym bólu i wyjaśnia zasadę, że od Bash 4.3.46 nie można pobrać pliku crontab.

Arcticooling
źródło