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

266

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

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

Джеймс
источник

Ответы:

88

Пусть 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
Джонатан Леффлер
источник
246

Вы можете определить переменные окружения в самом 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"
carestad
источник
58
Обратите внимание, что вы не можете использовать подстановку переменных как в оболочке, поэтому объявление типа PATH = / usr / local / bin: $ PATH интерпретируется буквально.
Зак
8
Я смог установить переменные окружения в самом crontab под RedHat 4.4.7-3 и cronie-1.4.4-15.el6.x86_64
Бруно Ланге,
7
Вам не нужно экспортировать переменные, если переменные используются только внутри команды, просто добавьте их перед вашей командой. "* * * * * sleep 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
Вутран
@BrunoLange, не могли бы вы рассказать, как вам удалось их настроить?
Newskooler
145

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

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

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

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

Вишал
источник
Это сработало для меня после того, как изо всех сил пытался найти ответ, спасибо!
Владимир Монтеалегре
5
это не работало для меня, пока я не понял, что я пропустил тот период, предшествующий $ HOME. Что именно этот период делает?
flymike
9
Точка эквивалентна команде «источник»: tldp.org/LDP/abs/html/special-chars.html#DOTREF
Джефф W
@PeterLee что-нибудь упомянутое сработало для вас? Я написал это, так как вышеупомянутые решения не были эффективными для меня. Если вышеупомянутое решение не работает, мне придется провести некоторое исследование, чтобы найти причину. ;-)
Вишал
3
@Vishal На самом деле, теперь это работает для меня. Я пытался source ~/.bashrc, и оказалось, что мой .bashrcфайл как бы конфликтует с заданием cron. Если я использую очень простой .env_setup_rcфайл с одной строкой: export MY_ENV_VAR=my_env_valон действительно работает. Смотрите мой пост: stackoverflow.com/questions/15557777/…
Питер Ли
63

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

Аугусто Дестреро
источник
11
Лучший ответ, просто выполните, env >> /etc/environmentи все текущие переменные env теперь доступны в заданиях CRON.
Savageman
6
это прекрасно работает для меня. тем более, что я работаю с Docker-контейнером, поэтому меня не волнуют последствия для всей системы.
Лукас Поттерский
14
@Savageman - это все равно, что убивать мух с помощью термоядерных бомб, а ставки неожиданного поведения чрезвычайно высоки.
Фран Марзоа
2
Будьте ОСТОРОЖНЫ: потерпит env >> /etc/environmentнеудачу, если в одной из переменных среды есть хэш Мне было труднее всего устранить неполадки в моем приложении. Это оказался пароль, содержащий «#», который усекался на этом этапе.
ASAC
3
Это должен быть выбранный ответ. Я не знаю, почему люди усложняют другие ответы или что-то подобное в среде env >> / etc / environment. Просто мигните, отредактируйте etc / environment, если вы хотите, чтобы эти env-переменные были универсально доступны: мои эксперименты, кажется, подтверждают, что операторы экспорта для env-переменных в / etc / environment доступны для crontab, а также для пользователей. ПРОБЛЕМА: опять же из моих экспериментов: кажется, что эти envvars НЕ РАСШИРЕНЫ в самом crontab! ... т.е. они раскрываются только в скриптах, которые называются!
Майк Грызун
39

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

#!/bin/bash -l

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

breizhmg
источник
4
Этот ответ должен получить больше голосов и просто быть выбранным ответом: очень простой и элегантный и избегает бесчисленных ошибок, которые потребуют перепрыгивания через всю систему.
JakeGould
Мне нравится этот ответ +1. Может / Должно ли это использоваться при запуске rootcrontab? В /home/rootмоей системе нет папки, и поэтому я не вижу, как это будет работать с rootcrontab. Идеи?
Симус
В самом сценарии. Который вы тогда запускаете с cron нормально
Breizhmg
@ Джим, смотрите этот пример , используйте классический исполняемый файл (chmod 777) #!/bin/bash. Волшебство здесь, чтобы добавить-l
Питер Краусс
22

Расширение примера @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 будет иметь вашу среду, как если бы вы вошли в систему.

Роберт Брисита
источник
16

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

$ sudo  crontab -e

кронтаб:

ENVIRONMENT_VAR=production

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

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

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

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

karlingen
источник
Это не сработало для меня. Переменная окружения не была доступна в скрипте, который был вызван внутри crontab.
Нихилу
12

Все, что вы установили, 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
...
Федорки "ТАК прекратить вредить"
источник
7

Расширение @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
Маркос Поусада
источник
7

Вместо того

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

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

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Илья Харламов
источник
1
Почему это вместо того, чтобы просто иметь объявление Bash в верхней части файла, -lнапример #!/bin/bash -l:? Этот другой ответ прост и элегантен.
JakeGould
1
Что если мне нужно запустить скрипт perl / python / ruby, а не bash? Я не могу добавить #! / Bin / bash -l в начало скрипта Python.
Илья Харламов
«Что если мне нужно запустить скрипт perl / python / ruby, а не bash?» Справедливо. Но, на мой взгляд, вы можете написать простую оболочку Bash-скрипта, которая затем вызывает скрипт Python. Я делаю аналогичные вещи для сценариев PHP. Причина в том, что блокировка процессов намного лучше и надежнее в Bash, но сценарии Bash все еще являются головной болью. Поэтому я написал материал на PHP для сложных вещей и позволил Bash справиться со всем остальным.
JakeGould
3

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

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

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

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

Stiakov
источник
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
Сокир
источник
2

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

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

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

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

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

Абду
источник
0

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

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
источник