Gdzie mogę ustawić zmienne środowiskowe, których będzie używać crontab?

266

Co godzinę mam crontab. Użytkownik, który go uruchamia, ma środowisko niezmienne w tym, .bash_profilektóre działa, gdy użytkownik uruchamia zadanie z terminala, ale oczywiście nie są one odbierane przez crontab podczas jego działania.

Próbowałem, ustawiając je w .profilea .bashrcjednak wciąż nie wydają się podniósł. Czy ktoś wie, gdzie mogę umieścić zmienne środowiskowe, które Crontab może odebrać?

James
źródło

Odpowiedzi:

88

Niech „cron” uruchomi skrypt powłoki, który ustawia środowisko przed uruchomieniem polecenia.

Zawsze.

#   @(#)$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

Wszystkie skrypty w ~ / bin / Cron są linkami do jednego skryptu „runcron”, który wygląda następująco:

:       "$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 ${@:+"$@"}

(Napisane przy użyciu starszego standardu kodowania - w dzisiejszych czasach na początku używałbym przekreślenia „#!”).

„~ / .Cronfile” to odmiana w moim profilu do użytku przez crona - rygorystycznie nieinteraktywna i bez echa ze względu na bycie głośnym. Zamiast tego możesz skonfigurować plik .profile i tak dalej. (Rzeczy REAL_HOME to artefakt mojego środowiska - możesz udawać, że jest taki sam jak $ HOME.)

Tak więc ten kod odczytuje odpowiednie środowisko, a następnie wykonuje wersję polecenia inną niż Cron z mojego katalogu domowego. Na przykład moje polecenie „dzień tygodnia” wygląda następująco:

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

# Update ICSCOPE
n.updics

Polecenie „codzienne” jest prostsze:

:       "@(#)$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
źródło
246

Możesz definiować zmienne środowiskowe w samym crontabie, gdy uruchamiasz crontab -ez wiersza poleceń.

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

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

Ta funkcja jest dostępna tylko dla niektórych implementacji crona. Ubuntu i Debian używają obecnie vixie-cron, co pozwala zadeklarować je w pliku crontab (także GNU mcron ).

Archlinux i RedHat używają cronie, który nie pozwala na zadeklarowanie zmiennych środowiskowych i wyrzuca błędy składniowe w pliku cron.log. Obejście można wykonać dla każdego wpisu:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
Carestad
źródło
58
Zauważ, że nie możesz używać podstawiania zmiennych jak w powłoce, więc deklaracja taka jak PATH = / usr / local / bin: $ PATH jest interpretowana dosłownie.
Zac
8
Udało mi się ustawić zmienne środowiskowe w samym crontabie pod RedHat 4.4.7-3 i cronie-1.4.4-15.el6.x86_64
Bruno Lange
7
Naprawdę nie musisz eksportować zmiennych, jeśli zmienne są używane tylko w poleceniu, po prostu wstaw je przed poleceniem. „* * * * * spać 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL”
vutran
@BrunoLange czy możesz podzielić się tym, jak udało Ci się je skonfigurować?
Newskooler
145

Mam jeszcze jedno rozwiązanie tego problemu:

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

W takim przypadku wybierze wszystkie zmienne środowiskowe zdefiniowane w $HOME/.profilepliku.

Oczywiście $HOMErównież nie jest ustawiony, musisz zastąpić go pełną ścieżką $HOME.

Vishal
źródło
To zadziałało dla mnie po wielu próbach znalezienia odpowiedzi, dzięki!
vladimir montealegre
5
nie działało to dla mnie, dopóki nie zdałem sobie sprawy, że opuściłem okres poprzedzający $ HOME. Co dokładnie robi ten okres?
flymike
9
Ta kropka odpowiada komendzie „source”: tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W
@PeterLee czy coś wspomnianego działało dla Ciebie? Napisałem to, ponieważ wyżej wymienione rozwiązania nie były dla mnie skuteczne. Jeśli powyższe rozwiązanie nie zadziała, będę musiał przeprowadzić badania, aby znaleźć przyczynę. ;-)
Vishal
3
@ Vishal Właściwie to działa teraz dla mnie. Próbowałem source ~/.bashrci okazuje się, że mój .bashrcplik jest w pewnym sensie sprzeczny z zadaniem cron. Jeśli użyję bardzo prostego .env_setup_rcpliku z tylko jedną linią: export MY_ENV_VAR=my_env_valto faktycznie działa. Zobacz mój post: stackoverflow.com/questions/15557777/...
Peter Lee
63

Ustawienie vars /etc/environmentrównież działało dla mnie w Ubuntu. Od 12.04 zmienne /etc/environmentsą ładowane dla crona.

Augusto Destrero
źródło
11
Najlepsza odpowiedź, po prostu wykonaj, env >> /etc/environmenta wszystkie bieżące zmienne środowiskowe są teraz dostępne w zadaniach CRON.
Savageman,
6
to działa świetnie dla mnie. tym bardziej, że wpadam na kontener Docker, więc nie dbam zbytnio o konsekwencje dla całego systemu.
Lucas Pottersky
14
@ Savageman, który przypomina zabijanie much za pomocą bomb termojądrowych, również ryzyko nieoczekiwanego zachowania jest bardzo wysokie.
Fran Marzoa,
2
Bądź ostrożny: env >> /etc/environmentnie powiedzie się, jeśli w jednej ze zmiennych środowiskowych znajduje się znak skrótu. Trudno mi było rozwiązać problem z aplikacją. Okazało się, że jest to hasło zawierające „#”, które na tym etapie zostało obcięte.
asac
3
To powinna być wybrana odpowiedź. Nie wiem, dlaczego ludzie komplikują inne odpowiedzi lub te rzeczy na temat env >> / etc / environment. Po prostu dobrze migaj edytuj etc / environment, jeśli chcesz, aby te zmienne env były powszechnie dostępne: moje eksperymenty wydają się potwierdzać, że instrukcje eksportu dla zmiennych env w / etc / environment są dostępne dla crontab, a także dla użytkowników. PROBLEM: ponownie z moich eksperymentów: wydaje się, że te zmienne środowiskowe NIE SĄ ROZSZERZONE w samym crontabie! ... tzn. są one rozwijane tylko w skryptach o nazwie!
Mike Rodent
39

Jeśli uruchamiasz skrypty, które wykonujesz za pomocą crona:

#!/bin/bash -l

Powinny wybrać twoje ~/.bash_profilezmienne środowiskowe

breizhmg
źródło
4
Ta odpowiedź powinna uzyskać więcej pozytywnych opinii i być po prostu wybraną odpowiedzią: bardzo prosta i elegancka i pozwala uniknąć niezliczonych kłopotów, które wymagałyby przeskakiwania po całym systemie.
JakeGould,
Podoba mi się ta odpowiedź +1. Czy można / należy tego użyć podczas uruchamiania rootcrontab? W /home/rootmoim systemie nie ma folderu, więc nie widzę, jak to by działało z rootcrontabem. Pomysły?
Seamus
W samym skrypcie. Które następnie normalnie uruchamiasz z cronem.
breizhmg
@Jim zobacz ten przykład , użyj klasycznego pliku wykonywalnego (chmod 777) #!/bin/bash. Magia polega na dodaniu-l
Peter Krauss
22

Rozwijając przykład @carestad, który jest dla mnie łatwiejszy, można uruchomić skrypt za pomocą crona i mieć w nim środowisko.

W pliku crontab -e:

SHELL=/bin/bash

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

W pliku cron_job.sh:

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

Każde polecenie po źródle pliku .bash_profile będzie miało środowisko tak, jakbyś się zalogował.

Robert Brisita
źródło
16

Dla mnie musiałem ustawić zmienną środowiskową dla aplikacji php. Przesadziłem go, dodając następujący kod do mojego pliku crontab.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

i wewnątrz doSomethingWonderful.php Mógłbym uzyskać wartość środowiska za pomocą:

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

Mam nadzieję, że to pomoże!

karlingen
źródło
To mi nie zadziałało. Zmienna środowiskowa nie była dostępna w skrypcie, który został wywołany w pliku crontab.
Nikhil
12

Cokolwiek ustawisz, crontabbędzie dostępne w cronjobs, zarówno bezpośrednio, jak i przy użyciu zmiennych w skryptach.

Użyj ich w definicji współdziałania

Możesz skonfigurować crontabtak, aby ustawiał zmienne, z których następnie może korzystać cronjob:

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

Teraz plik /tmp/hellopokazuje takie rzeczy jak:

$ 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

Użyj ich w skrypcie prowadzonym przez cronjob

Możesz skonfigurować crontabtak, aby ustawiał zmienne, których następnie mogą używać skrypty:

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

Powiedzmy, że skrypt /tmp/myscript.shwygląda tak:

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

Generuje plik /tmp/myoutput.respokazujący:

$ 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 przestań szkodzić”
źródło
7

Rozwijanie w @Robert Brisita właśnie się rozszerzyło, również jeśli nie chcesz konfigurować wszystkich zmiennych profilu w skrypcie, możesz wybrać zmienne do wyeksportowania na górze skryptu

W pliku crontab -e:

SHELL=/bin/bash

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

W script.sh

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

some-other-command
Marcos Pousada
źródło
7

Zamiast

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

Użyj bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
źródło
1
Dlaczego zamiast tego tylko deklaracja Bash na górze pliku ma następującą -lpostać #!/bin/bash -l:? Ta inna odpowiedź jest prosta i elegancka.
JakeGould,
1
Co jeśli muszę uruchomić skrypt perl / python / ruby, nie bash? Nie mogę dodać #! / Bin / bash -l na górze skryptu Pythona.
Ilya Kharlamov
„Co jeśli muszę uruchomić skrypt perl / python / ruby, a nie bash?” Słusznie. Ale moim zdaniem możesz napisać proste opakowanie skryptu Bash, które następnie wywołuje skrypt w języku Python. Podobnie robię dla skryptów PHP. Powodem jest to, że blokowanie procesów jest o wiele lepsze i niezawodne w Bash, ale skrypty Bash wciąż sprawiają ból głowy. Więc napisałem rzeczy w PHP dla skomplikowanych rzeczy i pozwól Bash zająć się resztą.
JakeGould,
3

Używam Oh-my-zshw moim Macbooku, więc próbowałem wielu rzeczy, aby uruchomić zadanie crontab, ale w końcu moim rozwiązaniem było przygotowanie .zshrcprzed uruchomieniem polecenia.

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

To zadanie jest uruchamiane co 30 minut i używa .zshrcprofilu do wykonania polecenia węzła.

Nie zapomnij użyć kropki przed $HOMEvar.

Stiakow
źródło
2

Innym sposobem - zainspirowanym tą odpowiedzią - na „wstrzyknięcie” zmiennych jest następujący (przykład fcron):

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

Od help set:

-a Zaznacz zmienne, które są modyfikowane lub tworzone do eksportu.

Użycie + zamiast - powoduje wyłączenie tych flag.

Tak więc wszystko pomiędzy set -i set +zostaje wyeksportowane do envi jest następnie dostępne dla innych skryptów itp. Bez użycia setzmiennych pozyskiwane są źródła, ale żyją settylko w.

Poza tym przydatne jest również przekazywanie zmiennych, gdy program wymaga konta innego niż root, ale potrzebujesz zmiennych w środowisku innego użytkownika. Poniżej znajduje się przykład przekazywania przez zmienne nullmailer do formatowania nagłówka wiadomości e-mail:

su -s /bin/bash -c "set -a; \
                    . /path/to/nullmailer-vars; \
                    set +a; \
                    /usr/sbin/logcheck" logcheck
Saucier
źródło
2

Próbowałem większości dostarczonych rozwiązań, ale na początku nic nie działało. Okazuje się jednak, że to nie rozwiązania nie działały. Najwyraźniej mój ~/.bashrcplik zaczyna się od następującego bloku kodu:

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

Zasadniczo jest to case statementsprawdzanie bieżącego zestawu opcji w bieżącej powłoce w celu ustalenia, czy powłoka działa interaktywnie. Jeśli powłoka działa interaktywnie, przechodzi do pobierania ~/.bashrcpliku. Jednakże, powłoka wywołana przez cronThe $-zmienna nie zawiera iwartość, która wskazuje, interaktywność. Dlatego ~/.bashrcplik nigdy nie jest w pełni pozyskiwany. W rezultacie zmienne środowiskowe nigdy nie zostały ustawione. Jeśli to jest twój problem, skomentuj blok kodu w następujący sposób i spróbuj ponownie:

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

Mam nadzieję, że okaże się to przydatne

Abdou
źródło
0

Możesz również poprzedzić polecenie, envaby wstrzyknąć zmienne środowiskowe, takie jak:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
źródło