cron игнорирует переменные, определенные в «.bashrc» и «.bash_profile»


49

Я определил переменную "SHELL" в файле / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

Кроме того, все мои скрипты в файле / etc / crontab запускаются под пользователем "martin". Однако /home/martin/.bash_profile (для оболочки входа в систему) и /home/martin/.bashrc (для оболочки без регистрации) содержат некоторые переменные, которые игнорируются в случае задания cron, но используются в случае, если я захожу в машину через SSH или откройте новую сессию bash. Почему cron игнорирует эти переменные? Разве cron просто не выполняет "/ usr / local / bin / bash my-script.sh" с разрешениями для пользователя "martin"?


2
Пользователи Ubuntu могут заметить, что по умолчанию в Ubuntu .bashrcесть строка, которая не позволяет ему работать в неинтерактивных оболочках.
Joeytwiddle

Ответы:


72

Вы можете найти нужный файл в верхней части скрипта или в начале задания для пользователя, выполняющего задание. Команда «source» является встроенной. Вы сделали бы то же самое, если бы вы вносили изменения в эти файлы для загрузки изменений.

* * * * * source /home/user/.bash_profile; <command>

или же

#!/bin/bash
source /home/user/.bash_profile

<commands>

2
Обратите внимание, что «source» может не работать, если cron не использует bashоболочку. Я добавил ответ, который может обработать случай, когда оболочка sh.
Джонатан


23

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

Посмотрите на этот вопрос: что такое файл .bashrc? | Супер пользователь

А также на этот:

В чем разница между .bashrc, .bash_profile и .environment? | Переполнение стека

Различные сценарии запускаются в зависимости от того, является ли соединение оболочкой входа в систему (или нет), интерактивной оболочкой (или нет) или обоими.

Если вы хотите сделать bashrc, вам нужно внести следующие изменения:

Когда Bash запускается неинтерактивно, например, для запуска сценария оболочки он ищет переменную BASH_ENV в среде, расширяет ее значение, если оно там появляется, и использует расширенное значение в качестве имени файла для чтения и выполнения. , Bash ведет себя так, как будто была выполнена следующая команда:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

но значение переменной PATH не используется для поиска имени файла.

Как отмечалось выше, если с помощью этой --loginопции вызывается неинтерактивная оболочка , Bash пытается читать и выполнять команды из файлов запуска оболочки входа в систему.

Источник: Bash Startup Files | Bash Справочное руководство | gnu.org


Поэтому, если мы установим BASH_ENV внутри Cron, сценарии cron bash будут исходить из этого, потому что cron неинтерактивен и не входит в систему.
CMCDragonkai

13

Вы не сможете запустить, sourceесли используется shоболочка. Это можно изменить, добавив следующую строку в ваш crontab:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Вы также можете указать среду:

BASH_ENV="/root/.bashrc"
* * * * * <command>

или вы можете использовать свой локальный, /home/user/.bashrcесли это пользовательская работа cron (например crontab -e).

Обратите внимание, что .bash_profileможно заменить .bashrc, если он существует.

Кредит: Как изменить оболочку cron (sh на bash)?


Это хорошо работает и для запланированных заданий Acquia Cloud, которые в основном являются заданиями cron. Вы можете сделать то же самое, как:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Алехандро Морено

1

Что-то еще, что может помешать получению вашего источника .bashrcиз cronjob, - это любые проверки, выполняемые этим файлом для обнаружения интерактивных оболочек.

Например, в Ubuntu 18.04 значение .bashrcпо умолчанию для пользователя начинается с этого:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

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


1

Вы можете вызвать bash с -lопцией, например так:

* * * * * /bin/bash -l /path/to/script arg1 arg2

-lОпция делает Баш в регистрационную оболочку. Таким образом, он будет читать пользователя .bash_profile. Он не будет читать пользователя, .bashrcесли он явно не получен .bash_profile. Это потому, что неинтерактивные оболочки не читаются автоматически .bashrc. Но вам не нужно .bashrcвыполнять работу cron, потому что она .bashrcпредназначена для настройки вещей, полезных для интерактивной оболочки.

Варианты:

Если bash находится в PATH, нет необходимости указывать абсолютный путь:

* * * * * bash -l /path/to/script arg1 arg2

Оптимизация будет состоять в том, чтобы заменить текущую оболочку с помощью exec:

* * * * * exec bash -l /path/to/script arg1 arg2

1

bashдействует по-разному, будь то оболочка или обычный язык программирования (например, perlили python).

В соответствии с проектом, настройки ~/.bash_profile, ~/.bashrcи т.д., для пользователей , чтобы установить вещи , когда bashиграет роль оболочки (Войти оболочки, interractive оболочки). Подумайте о среде, в которой вы находитесь xterm(интерактивная оболочка) или sshсеансах (оболочка входа в систему) или в консолях (оболочка входа в систему).

С другой стороны, bashэто также мощный язык программирования - подумайте о многих сценариях для управления службами, systemd- который требует другого стиля работы. Например, когда разработчик пишет системный скрипт или bashпрограмму, он / она не хочет автоматически получать исходный текст пользователя ~/.bash_profile. Это нормальная программа, а не оболочка. Обычная программа (включая bashпрограммы) естественным образом наследует настройки от текущего рабочего средства (оболочки), но не устанавливает их.

Если мы напишем программу для cronin bash- это просто произойдет bash; на самом деле, мы можем записать его в pythonили perlили любой другой progamming Язык- тогда мы можем иметь опцию источники bash«s ~/.bash_profile(читай: настройка оболочки пользователя, который как раз случается быть тот же язык вашего языка программирования):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

Однако что, если этот конкретный пользователь не использует в bashкачестве своей оболочки? Он / она может использовать zsh, ksh, fishи т.д. Таким образом, эта практика будет на самом деле не работать при написании программы для общественного пользования.

Таким образом, вы можете найти источник, ~/.bash_profileесли вы думаете, что это сработает. Но здесь речь идет не о том, можем ли мы получить файл, а о том, как все должно работать в системе: концепции дизайна . Вкратце: мы должны рассматривать bashкак нечто, имеющее 2 роли: оболочку и язык программирования . Тогда все будет намного легче понять.


0

У меня возникла та же проблема при выполнении приложения узла из cron, которое использует NVM. Чтобы сделать оболочку bash для чтения файла .bashrc из cron, просто вызовите команду bash с параметром интерактивной оболочки `-l.

например: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Если это не сработает, попробуйте установить переменную path в crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "

-1

Мой способ справиться с этим заключался в следующем:

1) Поместить мои переменные в (конец) ~/.profile:

myVarInDotProfile="someValue"

2) Создание Bash-скрипта для моих (ежедневных) задач cron ( ~/cronDaily.sh), содержащего мои команды плюс повторяющиеся источники ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) составление расписания выполнения моего сценария crontabдля ежедневного запуска:

0 0 * * * bash ~/cronDaily.sh

Моя переменная не была проигнорирована, и команды были успешно выполнены.


Некоторые могут сказать, что такой интенсивный источник ~/.profileпроблематичен. В моем конкретном случае я не понимаю, почему это проблема, но я бы посоветовал создать для этого специальный файл.

В общем, возможно, есть лучший путь к этому, но это то, что сработало для меня после большой боли, и это объясняет принцип, что с Bash 4.3.46 вы не можете получить файл из crontab.

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