Как запустить команду cron с существующими переменными среды?


114

Как запустить команду cron с существующими переменными среды?

Если я в командной строке, я могу набрать echo $ORACLE_HOMEи получить путь. Это одна из моих переменных окружения, которая устанавливается в моем ~/.profile. Тем не менее, кажется, что ~/.profileне загружаются сценарии fron cron и поэтому мои сценарии завершаются ошибкой, потому что $ORACLE_HOMEпеременная не установлена.

В этом вопросе автор упоминает о создании ~/.cronfileпрофиля, который устанавливает переменные для cron, а затем делает обходной путь для загрузки всех своих команд cron в скрипты, которые он хранит в своем ~/Cronкаталоге. Подобный файл ~/.cronfileзвучит как хорошая идея, но остальная часть ответа кажется немного громоздкой, и я надеялся, что кто-нибудь подскажет мне более простой способ получить тот же результат.

Я предполагаю, что в начале моих сценариев я мог бы добавить что-то вроде этого, source ~/.profileно, похоже, это может быть излишним.

Итак, как мне заставить мои скрипты cron загружать переменные из моего профиля интерактивной оболочки?


Как добавление source ~/.profileв программу избыточно? Программы наследуют свою среду от вызывающей программы. Если эта вызывающая программа не является вашей оболочкой, то как полученная программа получит ту среду, которая вам нужна?
Arcege

Я уже написал свой ответ на подобный вопрос здесь. Он просто используется su -lдля настройки нормальной среды входа в систему, включая $ PATH для пользователя root или другого конкретного пользователя.
Tasket

Ответы:


141

В crontab перед командой добавьте . $HOME/.profile. Например:

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

Cronничего не знает о вашей оболочке; он запускается системой, поэтому он имеет минимальную среду. Если ты хочешь чего-то, тебе нужно это внести в себя.


14
Что делает .сценарий перед сценарием? (не уверен, как бы я это manсделал). Почему это отличается от source?
cwd

25
Команда .является исходной командой для source. Они эквивалентны внутри оболочки и их немного легче набирать, особенно внутри crontab. Чтобы получить больше информации, введите help .или выполните поиск ^SHELL BUILTIN COMMANDSна странице man для zshbuiltins bashили в верхней части ее. man ` . Running Скажет вам, что команда является встроенной.
Arcege

9
В зависимости от дистрибутивов Linux вам может потребоваться изменить .profileна .bash_profile. Проверьте, какой .profileфайл существует в домашнем каталоге пользователя.
Морозный Z

@Arcege Это не работает для меня (Fedora Core 21), и я предполагаю, что это потому, что уровень оболочки снова падает. Вместо этого, что работает, если вы его источник.
Ричард Т

3
Вероятно, что если он не работает, то это потому, что SHELL для скрипта cron не настроен на bash, поэтому он не выполняется так, как вы ожидаете.
Даниэль Фаррелл

40

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


5
При работе на AWS Linux AMI мне даже не приходило в голову, что cron не будет использовать /bin/bashв качестве оболочки. Я продолжал задаваться вопросом, почему такие вещи cd /path/to/project; source .varsработают, когда я набираю их вручную, но не выполняются ( File not found) при включении в cronjob. Ключевой чертой для меня была настройка, SHELL=/bin/bashчтобы я мог использовать знакомые команды bash в каждом cronjob. /bin/sh/(оболочка cron по умолчанию, по-видимому) очень ограничивает.
Хартли Броуди

Жаль, что вы не можете указывать файлы среды в верхней части cron, как вы можете указать отдельные переменные среды. У Systemd есть EnvironmentFileсервисный центр . Жаль, что у cron нет ничего похожего.
Радтек

вы заставляете все сценарии использовать / bin / bash во всех файлах crontab, что не очень хорошая идея, а также то, что касается строки cron: * / 1 * * * * $ HOME / cron_job.sh… * / 1 хорошо для ЧЕГО ?!? одна звезда означает, что она будет выполняться каждую минуту / 1 означает, что она будет выполняться каждую минуту. Как ответ в умном сообществе, это отвратительный грех, теперь я полагаю, что вы очень смущены, говоря лучшим… извините
THESorcerer

1
Это то, что называется примером. Не стесняйтесь приспосабливаться к вашим потребностям или не использовать его вообще. Разные штрихи для разных людей.
Роберт Брисита

4
Если $SHELLесть /bin/sh, sourceкоманда не существует. Используйте .вместо этого.
Мелле

18

Другой вариант, который я считаю более простым, - это запустить скрипт с помощью cron и указать bash для входа (следовательно, используя /etc/profile.d/...определения среды)

В crontab -eфайле:

*/1 * * * * bash -l -c './cron_job.sh'
*/1 * * * * bash -l -c 'php -f ./cron_job.php'

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


10

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


Я согласен с @fpmurphy, что это также обеспечивает безопасную среду процесса. Если вы хотите установить только несколько переменных из cron, вы можете использовать /usr/bin/envкоманду для установки переменных, а затем действовать как процесс окружения для cronjob.
Нихил Малли

Наenvdir ум приходит и daemontools .
sr_

6
Я полностью за безопасность, но, возможно, я могу создать файл ~/.cronvarsи включить его в профиль, а также в свои скрипты cron. Я не хочу жестко кодировать переменные среды в каждом из скриптов, которые я запускаю, потому что, когда пути меняются жестко закодированными путями в каждом файле, их нелегко поддерживать. Похоже, это позволит централизованно разместить необходимые переменные и при этом не будет загружать другие переменные.
cwd

4

Этот синтаксис определенно помогает вам. Я не понимаю синтаксис, но он работает. Oracle использует этот синтаксис при развертывании Oracle Configuration Manager в crontab, поэтому я считаю, что это правильное решение.

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters

2

Недавно я столкнулся со случаем, когда мне нужно было выполнить общий cronjob от имени пользователя root, но в то же время мне пришлось выполнить подкоманду от имени другого пользователя (что требовало использования среды этого пользователя). Я пошел со следующим подходом:

# m  h  dom  mon  dow  user  command
*/5  *   *    *    *   root  (sudo -i -u <the user> command-to-be-run-as-user) && command-to-be-run-as-root

Важной частью является -iпередаваемый аргумент , sudoкоторый будет выполнять данную команду в отдельной оболочке входа в систему (что, в свою очередь, означает, что точечные файлы пользователя будут получены).

PS: обратите внимание, что userстолбец доступен только в /etc/crontabи /etc/cron.d/*файлы.


1

Решение, которое сработало для меня, описано здесь .

Вы создаете скрипт-обертку, который вызывает . ~/.cronfile, а затем делает то, что вам нужно. Этот скрипт запускается cron.

В ~/.cronfileвы указываете среду для ваших заданий cron.


1

Да, вы можете использовать «общеизвестные обходные пути» (несколько из которых были перечислены). Это еще один способ сказать, что все знают, что это дерьмо, хотя некоторые люди будут называть это «функцией безопасности», потому что они потратили, по крайней мере, столько же срабатываний на этот сбой, чем вы, и хотели бы думать, что их потерянное время не было напрасно. Это cron-эквивалент QWERTY-клавиатуры.

Я подозреваю, что первоначальная причина, возможно, была в производительности, так что скрипты, запускаемые раз в минуту, не тратили бы время на чтение скриптов rc. Также изначально cron вообще не был настраиваемым, так что по умолчанию был единственным вариантом.

Там нет дополнительной безопасности, потому что нет простой конфигурации или метода, чтобы cron просто использовал среду вашей интерактивной оболочки вместо того, чтобы пользователи выполняли глупую гимнастику оболочки. На современном компьютере, как правило, заметного прироста производительности нет, если у вас не выполняется огромное количество заданий в минуту.

Культура Unix провалилась. По моему "скромному" мнению. :-)


1
«Там нет дополнительной безопасности». Это неправда. Взгляните на CVE-2011-1095 , CVE-2008-4304 и CVE-2010-3847 .

Кстати, я отклонил ваш ответ. Я обычно стараюсь избегать занижения ответов новичков, но для меня важна безопасность. Пожалуйста, не принимайте отрицательный ответ. Помимо части о безопасности, ваш ответ превосходен и заслуживает одобрения. Вы можете редактировать свой ответ здесь, если хотите.

Ни один из них не имеет ничего общего с тем, чтобы cron использовал оболочку с установленным интерактивным флагом. Это чистый фуд. К сожалению, я не могу понизить ваш голос. Это может показаться пламенем, но очень расстраивает, когда люди думают, что автомобиль с тремя колесами лучше, потому что есть проблема безопасности, чтобы поставить четвертое колесо. Это не так. Люди только что ездили на трехколесном велосипеде, так долго, что они забыли, что можно добавить четвертое колесо.
Остин С.

Другими словами, если используются какие-либо из предполагаемых дополнительных пялец, предложенные другими авторами, как они также не получают доступ ни к одной из упомянутых вами дыр? "* * * * * exec bash -i -c LOCALE = ......."
Остин С.

Это читается как напыщенная речь. Я даже не вижу, где это отвечает на вопрос вообще. Даже если часть безопасности была удалена, @EvanTeitelman, я не понимаю, почему это заслуживает повышения, поскольку не отвечает на вопрос.
Wildcard


1

Вместо того, чтобы устанавливать профиль, мне помогло установить PATH. Некоторые команды не были доступны в моих скриптах cron, так как они PATHразные.

ENVIRONMENT=prod
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Установка PATHс путем команд помогла мне. Еще лучше, если вы можете использовать шаблон и позже подвергать детламентации,

ENVIRONMENT={{ENVIRONMENT}}
PATH={{PATH}}
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

Передача переменных каждому элементу выглядит грязно.


-1

Я кладу . ~/.dbus/session-bus/*в верхней части моего желаемого сценария :)


1
Добро пожаловать в U & L SE. Пожалуйста, расширьте свой ответ больше, чтобы он принес пользу читателям.
Рамеш,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.