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

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

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

20 ответов

Решение

Пусть cron запустит скрипт оболочки, который устанавливает среду перед запуском команды.

Всегда.

#   @(#)$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 - это ссылки на один скрипт, 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 ${@:+"$@"}

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

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

Вы можете определить переменные окружения в самом 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"

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

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

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

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

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

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

#!/bin/bash -l

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

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

В файле crontab -e:

SHELL=/bin/bash

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

В файле cron_job.sh:

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

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

Что бы вы ни выбрали 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

Используйте их в скрипте, запущенном cronjob

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

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

И сказать сценарий /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
...

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

$ sudo  crontab -e

кронтаб:

ENVIRONMENT_VAR=production

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

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

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

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

Вместо

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

Используйте bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'

Вы также можете добавить свою команду с помощью env чтобы ввести переменные среды следующим образом:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand

Я использую Oh-my-zsh в моем macbook, поэтому я много чего пробовал, чтобы запустить задачу crontab, но, наконец, мое решение добавляло .zshrc перед командой для запуска.

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

Эта задача запускается каждые 30 минут и использует .zshrc профиль для выполнения моей команды узла.

Не забудьте поставить точку перед $HOME var.

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

В файле crontab -e:

SHELL=/bin/bash

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

В script.sh

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

some-other-command

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

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

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

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

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

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

Простым подходом будет следующий пример: предположим, что у вас есть переменные env в файле с именем env, тогда:

* * * * * . ./env && /path/to_your/command

эта часть . ./env экспортирует их, а затем они будут использоваться в той же области действия вашей команды

Другой способ - вдохновленный этим ответом - "вставить" переменные заключается в следующем (пример 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

Все вышеперечисленные решения работают нормально.

Это вызовет проблемы, если в вашей переменной среды есть какие-либо специальные символы.

Я нашел решение:

eval $(printenv | awk -F= '{print "export " "\""$1"\"""=""\""$2"\"" }' >> /etc/profile)

Мне пришлось указать путь в моем файле NodeJS.

// did not work!!!!!
require('dotenv').config()

вместо

// DID WORK!!
require('dotenv').config({ path: '/full/custom/path/to/your/.env' })

Я обнаружил эту проблему, глядя на аналогичную проблему, которая соответствует названию, но я застрял с синтаксисом файла среды, который используют systemd или docker:

      FOO=bar
BAZ=qux

Это не сработает для отличного ответа Вишала, потому что это не сценарии bash (обратите внимание на отсутствие export).
Решение, которое я использовал, - прочитать каждую строку в xargs и экспортировать их перед запуском команды:

      0 5 * * * export $(xargs < $HOME/.env); /path/to/command/to/run
  • Установить глобально env
sudo sh -c "echo MY_GLOBAL_ENV_TO_MY_CURRENT_DIR=$(pwd)" >> /etc/environment"
  • Добавить запланированное задание для запуска скрипта
crontab -e

  */5 * * * * sh -c "$MY_GLOBAL_ENV_TO_MY_CURRENT_DIR/start.sh"

знак равно

что сработало для меня (на основе Debian):

  1. создайте файл со всеми необходимыми env var:

    #! / bin / bash
    env | grep VAR1=> / etc / environment
    env | grep VAR2= >> / etc / environment
    env | grep VAR3= >> / etc / environment

  2. затем создайте содержимое crontab, вызвав файл env перед вызовом скрипта, который в нем нуждается, поэтому запустите службу cron

    (crontab -l; echo '* * * * *. / etc / environment; /usr / local / bin / python /mycode.py >> /var/log/cron-1.log 2>&1') | crontab
    сервис cron start

nb: для случая использования python обязательно вызовите весь путь python, иначе может быть вызван неправильный python, что приведет к бессмысленной синтаксической ошибке

Другие вопросы по тегам