Где я могу установить переменные окружения, которые будет использовать crontab?

224

У меня есть crontab, работающий каждый час. У пользователя, использующего его, есть среда без изменений в .bash_profile, которая работает, когда пользователь запускает задание с терминала, однако, очевидно, что они не подхватываются crontab при его запуске.

Я пробовал установить их в .profile и .bashrc, но они все еще, похоже, не подхватываются. Кто-нибудь знает, где я могу положить окружающие vars, которые может взять crontab?

  • 0
    Не могли бы вы рассмотреть вопрос об изменении принятого ответа на этот вопрос?
Теги:
environment-variables
crontab

13 ответов

79
Лучший ответ

Имейте "cron" запустите оболочку script, которая устанавливает среду перед запуском команды.

Всегда.

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

Скрипты в ~/bin/Cron - это все ссылки на один script, 'runcron', который выглядит так:

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

(Написано с использованием старого стандарта кодирования - в настоящее время я бы использовал shebang '#!' в начале.)

"~/.cronfile" - это вариант моего профиля для использования cron - строго неинтерактивный и не эхо, чтобы быть шумным. Вы могли бы организовать выполнение .profile и так далее. (Материал REAL_HOME является артефактом моей среды - вы можете притворяться, что это то же самое, что и $HOME.)

Итак, этот код читает соответствующую среду, а затем выполняет версию команды, отличную от Cron, из моего домашнего каталога. Так, например, моя команда "weekday" выглядит так:

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

# Update ICSCOPE
n.updics

"Ежедневная" команда проще:

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

Вы можете определить переменные среды в самом crontab при запуске crontab -e из командной строки.

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

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

Эта функция доступна только для некоторых реализаций cron. Ubuntu и Debian в настоящее время используют vixie-cron, которые позволяют объявлять их в файле crontab (также GNU mcron).

Archlinux и RedHat использовать cronie, который не позволяет разрешать переменные среды и будет вызывать синтаксические ошибки в cron.log. Обходное решение может быть выполнено для каждого входа:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
  • 47
    Обратите внимание, что вы не можете использовать подстановку переменных как в оболочке, поэтому объявление типа PATH = / usr / local / bin: $ PATH интерпретируется буквально.
  • 7
    Я смог установить переменные окружения в самом crontab под RedHat 4.4.7-3 и cronie-1.4.4-15.el6.x86_64
Показать ещё 3 комментария
120

У меня есть еще одно решение этой проблемы:

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

В этом случае он выберет всю переменную среды, определенную в файле $HOME/.profile.

Конечно, $HOME также не установлен, вы должны заменить его полным путем вашего $HOME.

  • 0
    Это сработало для меня после долгих попыток найти ответ, спасибо!
  • 5
    это не работало для меня, пока я не понял, что я пропустил тот период, предшествующий $ HOME. Что именно этот период делает?
Показать ещё 10 комментариев
34

Настройка vars в /etc/environment также работала для меня в Ubuntu. Начиная с 12.04, переменные в /etc/environment загружаются для cron.

  • 8
    Лучший ответ, просто выполните env >> /etc/environment и все текущие переменные env теперь доступны в заданиях CRON.
  • 4
    это прекрасно работает для меня. тем более, что я работаю с Docker-контейнером, поэтому меня не волнуют последствия для всей системы.
Показать ещё 1 комментарий
19

Расширение на примере @carestad, которое мне становится проще, - запустить script с помощью cron и создать среду в script.

В файле crontab -e:

SHELL=/bin/bash

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

В файле cron_job.sh:

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

Любая команда после источника .bash_profile будет иметь вашу среду, как если бы вы вошли в систему.

12

Для меня мне пришлось установить переменную окружения для приложения php. Я изменил его, добавив следующий код в мой crontab.

$ sudo  crontab -e

кронтаб:

ENVIRONMENT_VAR=production

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

и внутри doSomethingWonderful.php Я могу получить значение среды с помощью:

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

Надеюсь, это поможет!

10

Все, что вы установили в crontab, будет доступно в cronjobs, как напрямую, так и используя переменные в сценариях.

Используйте их в определении cronjob

Вы можете настроить crontab так, чтобы он устанавливал переменные, которые затем могут использовать cronjob:

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

Теперь файл /tmp/hello показывает такие вещи, как:

$ 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

Используйте их в script запустите cronjob

Вы можете настроить crontab так, чтобы он устанавливал переменные, которые могут использовать сценарии:

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

И скажем, что script /tmp/myscript.sh выглядит следующим образом:

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

Он генерирует файл /tmp/myoutput.res, показывающий:

$ 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
...
4

Вместо

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

Использовать bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
  • 0
    Почему вместо того, чтобы просто иметь объявление Bash в верхней части файла, используйте -l например: #!/bin/bash -l ? Этот другой ответ прост и элегантен.
  • 1
    Что если мне нужно запустить скрипт perl / python / ruby, а не bash? Я не могу добавить #! / Bin / bash -l в начало скрипта Python.
Показать ещё 1 комментарий
4

Расширение на @Robert Brisita просто расширяется, также если вы не хотите настраивать все переменные профиля в script, вы можете выбрать переменные для экспорта в верхней части script

В файле crontab -e:

SHELL=/bin/bash

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

В script.sh

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

some-other-command
2

Другим способом - вдохновленным этим этим ответом - для "инъекции" переменных является следующий (пример fcron):

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

От help set:

-a Отметить переменные, которые были изменены или созданы для экспорта.

Использование + вместо - приводит к отключению этих флагов.

Итак, все, что находится между set - и set +, экспортируется в env и затем доступно для других скриптов и т.д. Без использования set переменные получаются, но живут только в set.

Кроме того, полезно также передавать переменные, когда программе требуется выполнить учетную запись, отличную от root, но вам понадобятся некоторые переменные внутри этой другой пользовательской среды. Ниже приведен пример передачи в nullmailer vars для форматирования заголовка электронной почты:

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

Я попробовал большинство предоставленных решений, но сначала ничего не получилось. Оказывается, однако, что решения не работали. По-видимому, мой файл ~/.bashrc начинается со следующего блока кода:

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

В основном это оператор case statement который проверяет текущий набор параметров в текущей оболочке, чтобы определить, что оболочка работает в интерактивном режиме. Если оболочка работает интерактивно, она переходит к поиску файла ~/.bashrc. Однако в оболочке, вызываемой cron, переменная $- не содержит значение i которое указывает на интерактивность. Следовательно, файл ~/.bashrc никогда не получает полностью. В результате переменные среды никогда не были установлены. Если это будет вашей проблемой, не стесняйтесь комментировать блок кода следующим образом и повторите попытку:

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

Надеюсь, это окажется полезным

1

Если вы запускаете скрипты, которые выполняете через cron, с помощью:

#!/bin/bash -l

Они должны выбрать переменные среды ~/.bash_profile

  • 1
    Этот ответ должен получить больше голосов и просто быть выбранным ответом: очень простой и элегантный, избегающий бесчисленных ошибок, которые потребуют перепрыгивания через всю систему.
-2

Разработчики cron, если они обращают внимание, должны исправить этот кошмарно плохой дизайн. Программа, выполняемая в cron, должна работать так же, как при запуске из командной строки.

Это область, в которой Windows имеет это право. Когда вы запускаете программу через Windows Task Scheduler, она использует переменные среды Windows; вам не нужно предпринимать героические трюки, чтобы это произошло.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню