Почему этот скрипт дает сбой при запуске из cron, но работает при ручном запуске?

Почему этот скрипт дает сбой при запуске из cron, но работает при ручном запуске?

У меня есть относительно простой скрипт 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

Это не может считаться ответом, но я не могу комментировать. Предложения:

  1. Добавьте следующее в ваш скрипт 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файл
  2. Убедитесь, что скрипт будет запущен в другой среде. Укажите полный путь к 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. Работает?
  3. Имеет ли скрипт разрешение? Используете ли вы системный crontab? (опять же, вероятно, не виновник)

    • Вы указали, что используете системный crontab, поэтому пропустим этот шаг.
  4. Требуется ли apt-get поддержка сеанса (consolekit или systemd). Однако это всего лишь выстрел в темноту.

    • Недостаточно знаю, чтобы помочь.

решение3

Удалось решить ее, едва понимая, что происходит. Оказалось, что даже при запуске из root crontab, команды apt-get все еще требовали sudo перед собой. Логично, что я ожидал, что это не понадобится, поскольку скрипт уже выполнялся "как root", но как только я добавил sudo... все заработало именно так, как и ожидалось.

Связанный контент