У меня есть относительно простой скрипт bash, который отлично работает при прямом вызове, но дает сбой при запуске через cron. Почему он дает сбой и как заставить его работать через cron?
#!/bin/bash
apt-get update -y
apt-get upgrade -y
apt-get install boinc-client -y
После того, как cron попытается запустить его, ручной вызов приведет к следующей ошибке:
dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.
Но если запустить его вручную в первый раз, то все работает нормально.
решение1
Обычный ответ на этот тип вопросов заключается в том, что задания cron выполняются в неинтерактивных, неавторизированных оболочках, поэтому большинство ваших файлов запуска оболочки (как общесистемных, так /etc
и ваших личных dotfiles в вашем домашнем каталоге) не считываются (не считываются и не выполняются), поскольку большинство файлов запуска оболочки применяются к оболочкам входа (первая оболочка, которую вы видите при входе в систему) или интерактивным оболочкам (оболочкам, которые подключены к терминалам, сеансам ssh или эмуляторам терминала, поскольку пользователь взаимодействует с ними через указанный терминал).
Так что если вы поместите команду в задание cron, которое фактически зависит от некоторой настройки среды (включая PATH
изменения), которая обычно происходит в таких местах, как /etc/profile
, /etc/bashrc
, ~/.profile
, или ~/.bashrc
, эта настройка не произойдет для задания cron. Формат файла cron позволяет вам указывать переменные среды для ваших заданий, поэтому вы можете захотеть указать BASH_ENV
или ENV
указать на сценарий запуска оболочки для источника. Смотрите раздел «Вызов» на bash(1)
странице руководства.
решение2
Это не может считаться ответом, но я не могу комментировать. Предложения:
Добавьте следующее в ваш скрипт bash. Последняя строка, записанная в вывод mail, будет командой, завершившейся ошибкой.
set -x set -e
- убедитесь, что у вас есть sendmail (установите соответствующий пакет, например
postfix
илиesmtp
) - установить программу для чтения почты (рекомендуется
mutt
) - убедитесь, что почта дойдет до вас
- через постфикс (может быть сделано установщиком автоматически): добавить
root: my-user-name
в/etc/aliases
или/etc/postfix/aliases
- через cron: добавить
MAILTO="my-user-name"
в соответствующийcrontab
файл
- через постфикс (может быть сделано установщиком автоматически): добавить
- убедитесь, что у вас есть sendmail (установите соответствующий пакет, например
Убедитесь, что скрипт будет запущен в другой среде. Укажите полный путь к apt-get (вероятно, это не виновник, так как известно, что apt-get был найден) и запустите его в консоли (не терминале) вне X. (некоторые скрипты конфигурации dpkg требуют сеанса X).
- измените скрипт так, чтобы он использовал абсолютные пути, т.е.
/usr/bin/apt-get update -y
(замените на правильный путь) - переключитесь на консоль, нажав
ctrl-alt-f1
- переключитесь на пользователя root:
sudo -i
- запустить оболочку без входа в систему без среды:
env -i /bin/bash --noprofile --norc
(замените на правильный путь) - запустите скрипт:
/my/full/path/to/cronscript
. Работает?
- измените скрипт так, чтобы он использовал абсолютные пути, т.е.
Имеет ли скрипт разрешение? Используете ли вы системный crontab? (опять же, вероятно, не виновник)
- Вы указали, что используете системный crontab, поэтому пропустим этот шаг.
Требуется ли apt-get поддержка сеанса (consolekit или systemd). Однако это всего лишь выстрел в темноту.
- Недостаточно знаю, чтобы помочь.
решение3
Удалось решить ее, едва понимая, что происходит. Оказалось, что даже при запуске из root crontab, команды apt-get все еще требовали sudo перед собой. Логично, что я ожидал, что это не понадобится, поскольку скрипт уже выполнялся "как root", но как только я добавил sudo... все заработало именно так, как и ожидалось.