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