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

Вопрос или проблема

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

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

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

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

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

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

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

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

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

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

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

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

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

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters

Вы можете поместить глобальные переменные окружения в /etc/environment.
Они загружаются, когда программа запускается через crontab. Например:

env | grep ORACLE_HOME >> /etc/environment
service crontab restart

Недостаток в том, что это не ограничивается одним пользователем.
Проверено на CentOS7

Добавьте

BASH_ENV=/home/user/.profile

в crontab. См. Как гарантировать доступность $BASH_ENV

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

# m  h  dom  mon  dow  user  command
*/5  *   *    *    *   root  (sudo -i -u <пользователь> команда-для-выполнения-от-пользователя) && команда-для-выполнения-от-root

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

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

Вместо установки профиля, что помогло мне, так это установка 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

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

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

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

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

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

Автор вопроса спрашивал:

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

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

Менее громоздкий подход заключается в использовании опции --login у su, чтобы импортировать (почти) полное окружение пользователя. Это можно сделать без обращения к требованиям аутентификации, которые обычно сопровождают su – если он выполняется из root crontab.

Это может быть проиллюстрировано простым примером. Этот пример использует mpg123 – MP3-аудиоплеер. Однако многие другие примеры можно было бы создать из команд, которые (как mpg123) требуют различных переменных окружения для правильной работы, и эти переменные окружения часто устанавливаются без уведомления пользователя.

mpg123 можно обычно запустить из CLI без особых проблем. Например, чтобы воспроизвести файл в бесконечном цикле (после установления Bluetooth-соединения):

$ mpg123 --loop -1 ~/rainstorm.mp3

Но если мы попытаемся запустить это как задание cron, мы можем столкнуться с проблемами 🙂 Проблемы заключаются в том, что cron обычно имеет аскетичную среду, и mpg123 зависит от переменных окружения, которые не указаны (и неясны).

Мы можем решить эти проблемы следующим образом (pi – это пользователь pi):

  ... откройте root crontab
$ sudo crontab -e
   ... добавьте одну строку:

@reboot su pi -l -c /home/pi/start-mpg123.sh > /home/pi/start-mpg123.log 2>&1

start-mpg123.sh очень прост; он устанавливает Bluetooth-соединение, а затем запускает mpg123:

#!/usr/bin/bash

sleep 5
if [ "$(/usr/bin/bluetoothctl devices Connected)" != "Device DF:45:E9:00:BE:8B OontZ Angle solo DS E8B" ]; then
    /usr/bin/bluetoothctl connect DF:45:E9:00:BE:8B
fi
/usr/bin/mpg123 --loop -1 /home/pi/rainstorm.mp3

Я добавил . ~/.dbus/session-bus/* в начало своего скрипта 🙂

Ответ или решение

Для запуска cron-команды с уже определёнными переменными окружения есть несколько подходов, позволяющих избежать проблем с их отсутствием в среде выполнения cron. Вот несколько методов, которые помогут вам адаптировать cron для работы с вашими переменными окружения.

Понимание проблемы

По умолчанию cron работает в минимальной среде, которая не включает пользовательские переменные окружения, такие как ORACLE_HOME, определенные в вашем ~/.profile. При выполнении скриптов через cron, если переменные окружения не заданы явно, ваши команды могут завершиться с ошибками.

1. Импорт переменных из ~/.profile

Один из простых способов загрузки переменных окружения — это явное указание на файл .profile в вашем crontab. Для этого можно использовать следующую команду:

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

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

2. Использование оболочки с параметром -l

Другой подход заключается в запуске вашего скрипта через bash с параметром -l, который заставляет оболочку работать в режиме логина, тем самым загружая все настройки окружения:

*/1 * * * * bash -l -c '/path/to/cron_job.sh'

Внутри скрипта cron_job.sh вы можете использовать source для загрузки ~/.bash_profile:

#!/bin/bash
source $HOME/.bash_profile
# Другие команды

3. Объявление переменных окружения в самом crontab

Если вы знаете, какие переменные вам нужны, вы можете задать их прямо в crontab перед командой:

SOME_ENV_VAR=some_value /path/to/command

Этот подход позволяет избежать хранения конфигураций в отдельных файлах и делает ваш crontab более самодостаточным.

4. Использование глобального файла окружения

Если переменные окружения нужны для всех пользователей или задач в системе, вы можете добавить их в файл /etc/environment. Они будут доступны всем процессам, запущенным через cron. Например:

echo 'ORACLE_HOME=/path/to/oracle' | sudo tee -a /etc/environment

После изменения этого файла, вам нужно перезапустить службу cron:

sudo service cron restart

5. Создание "обёртки" для cron

Если вы ищете менее усложнённый способ, можно создать обёрточный скрипт, который будет загружать переменные окружения из отдельного файла. Например, создайте файл ~/.cronfile с необходимыми переменными:

export ORACLE_HOME=/path/to/oracle
export ANOTHER_VAR=value

А затем используйте этот файл в вашем crontab:

* * * * * . $HOME/.cronfile; /path/to/your/command

6. Использование sudo с -i

Если вам нужно запускать команды от имени другого пользователя и сохранить их окружение, вы можете использовать sudo -i:

@reboot sudo -i -u <username> /path/to/script.sh

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

Заключение

Каждый из предложенных методов имеет свои преимущества и недостатки. Выбор подхода зависит от ваших потребностей и конфигурации системы. Использование правильного метода позволит вам избежать излишних ошибок в cron-заданиях и обеспечит надлежащее выполнение скриптов в заданное время.

Оцените материал
Добавить комментарий

Капча загружается...