Як імітувати середовище cron виконує скрипт?


253

У мене зазвичай є кілька проблем з тим, як cron виконує сценарії, оскільки вони, як правило, не встановлюють моє середовище. Чи є спосіб викликати bash (?) Таким же чином, як це робить cron, щоб я міг перевірити скрипти перед їх встановленням?


Я хотів би запропонувати це рішення: unix.stackexchange.com/questions/27289 / ...
Rudi

Зробивши @gregseth трохи далі, я дав таке рішення: unix.stackexchange.com/questions/27289/…
Robert Brisita

Відповіді:


385

Додайте це до свого кронт (тимчасово):

* * * * * env > ~/cronenv

Після запуску зробіть це:

env - `cat ~/cronenv` /bin/sh

Це передбачає, що ваш cron працює / bin / sh, що є типовим, незалежно від оболонки користувача за замовчуванням.


5
Примітка: якщо ви додасте це до глобального / etc / crontab, вам також знадобиться ім'я користувача. Наприклад * * * * * root env> ~ / cronenv
Грег

10
Гарна, проста ідея. Для нетерплячих використовуйте '* * * * *', щоб запустити наступну хвилину, і не забудьте знову вимкнути, коли закінчите грати ;-)
Mads Buus

5
@Madsn Щоб повернутися до попередньої програми bash shell, спробуйте: exit
spkane

5
Важливість цієї відповіді не можна недооцінювати. Варто включення абзацу до книги.
Xofo

1
чи env - кішка ~ / cronenv` / bin / sh` також повинна бути записана як робота з кроном? будь ласка, наведіть приклад
JavaSa

61

Cron надає лише це середовище за замовчуванням:

  • HOME домашній каталог користувача
  • LOGNAME логін користувача
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

Якщо вам потрібно більше, ви можете надсилати скрипт, де ви визначаєте своє оточення перед таблицею планування в crontab.


7
.як правило , не входить PATHбільше, по міркувань безпеки .
l0b0

49

Пара підходів:

  1. Експорт cron env та джерело його:

    Додайте

    * * * * * env > ~/cronenv

    до свого кронтабу, нехай він працює один раз, вимкніть його, а потім запустіть

    env - `cat ~/cronenv` /bin/sh

    А ви зараз перебуваєте в shсесії, в якій є середовище cron

  2. Піднесіть своє оточення до крону

    Ви можете пропустити вище вправи і просто зробити . ~/.profileперед вашою роботою з крона, наприклад

    * * * * * . ~/.profile; your_command
  3. Використовувати екран

    Наведені вище рішення все ще не спрацьовують, оскільки вони забезпечують середовище, підключене до запущеного сеансу X, з доступом до dbusтощо. Наприклад, на Ubuntu nmcli(Менеджер мереж) буде працювати вище двох підходів, але все ще виходить з ладу в cron.

    * * * * * /usr/bin/screen -dm

    Додайте вище крон до рядка, нехай він працює один раз, вимкніть його. Підключіться до екранного сеансу (екран -r). Якщо ви перевіряєте, що створений сеанс екрана (з ps), пам’ятайте, що вони іноді знаходяться у великих літерах (наприклад ps | grep SCREEN)

    Зараз навіть nmcliі подібне не вдасться.


22

Ви можете запустити:

env - your_command arguments

Це запустить ваш_команда з порожнім середовищем.


4
cron не працює в абсолютно порожньому середовищі, чи не так?
jldupont

2
gregseth ідентифікував змінні, включені в середовище за допомогою cron. Ви можете включити ці змінні в командний рядок. $ env - PATH = "$ PATH" командні аргументи
DragonFax

4
@DragonFax @dimba Я використовую те, env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command argumentsщо, здається, робить трюк
l0b0

Це чудовий простий метод тестування сценаріїв у "ворожих" або невідомих середовищах. Якщо ви достатньо явні, що він буде працювати в цьому, він буде працювати під cron.
Олі


13

Відповідь через шість років: проблема невідповідності середовища є однією з проблем, яку systemd"таймери" вирішують як заміну крона. Незалежно від того, запускаєте ви системну "службу" від CLI або через cron, вона отримує абсолютно те саме середовище, уникаючи проблеми невідповідності оточення.

Найпоширенішою проблемою, яка може призвести до виходу з ладу завдань cron, коли вони проходять вручну, є обмежувальний за замовчуванням, $PATHвстановлений cron, що це в Ubuntu 16.04:

"/usr/bin:/bin"

На відміну від цього , за замовчуванням $PATHвстановлений systemdна Ubuntu 16.04 є:

"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Тож вже є більший шанс, що системний таймер знайде бінарний файл без зайвих клопотів.

Мінус системних таймерів - це трохи більше часу, щоб їх налаштувати. Ви спочатку створюєте "службовий" файл, щоб визначити, що ви хочете запустити, і "таймер", щоб визначити графік його запуску і, нарешті, "включити" таймер для його активації.


10

Створіть завдання cron, яке виконує env та перенаправляє stdout у файл. Використовуйте файл поряд із "env -", щоб створити таке ж середовище, що і завдання cron.


Вибачте, це мене бентежило. Чи недостатньо "env - script"?
Хорхе Варгас

Це дасть вам порожнє оточення. Під час запуску скриптів через cron середовище не порожнє.
Єнс Карлберг

3

Не забувайте, що оскільки батько cron є init, він запускає програми без керуючого терміналу. Ви можете імітувати це за допомогою такого інструменту:

http://libslack.org/daemon/


2

За замовчуванням cronвиконує свої завдання, використовуючи будь-яку ідею вашої системи sh. Це може бути фактичним Борна оболонка або dash, ash, kshабо bash(або інший) слінковано в sh(і , як наслідок , що працює в режимі POSIX).

Найкраще зробити, щоб переконатися, що у ваших сценаріях є те, що їм потрібно, і припустити, що їм нічого не передбачено. Тому вам слід використовувати повні специфікації каталогів та встановлювати змінні середовища, наприклад, $PATHви самі.


Це саме те, що я намагаюся вирішити. У нас виникають багато проблем зі сценаріями, які припускають щось помилково. Виконуючи повні шляхи та встановлюючи env-змінні, і всі мотлохи закінчуються жахливими величезними нездійсненними лініями кронів
Хорхе Варгас

re * sh вибачте, що я виріс bash = shell, тому мені важко запам’ятати альтернативні (а іноді й кращі) снаряди.
Хорхе Варгас

1
@Jorge: рядки в crontab повинні бути досить короткими. Ви повинні виконати всі необхідні налаштування в рамках сценарію (або сценарію обгортки). Ось типовий рядок із crontab як приклад: 0 0 * * 1 /path/to/executable >/dev/null 2>&1а потім, у межах "виконуваного файлу", я встановив би значення для $PATHтощо, і використовував повні специфікації каталогів для введення та виводу файлів тощо. Наприклад:/path/to/do_something /another/path/input_file /another/path/to/output_file
Призупинено до подальшого повідомлення.

1

Ще один простий спосіб, який я знайшов (але може бути схильним до помилок, я все ще тестую) - це джерело файлів профілю вашого користувача перед вашою командою.

Редагування сценарію /etc/cron.d/:

* * * * * user1 comand-that-needs-env-vars

Перетвориться на:

* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars

Брудно, але це зробило роботу для мене. Чи є спосіб імітувати логін? Просто команду, яку ти міг би виконати?bash --loginне працювало. Це здається, що це був би кращий шлях.

EDIT: Це, здається, є надійним рішенням: http://www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/

* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l

1

Прийнята відповідь дає спосіб запустити сценарій із середовищем cron. Як зазначали інші, це не єдиний необхідний критерій для налагодження робочих записів у системі.

Дійсно, cron також використовує неінтерактивний термінал, без вкладеного вводу тощо.

Якщо це допомагає, я написав сценарій, який дозволяє безболісно виконувати команду / сценарій, як це було б запущено cron. Викликайте це своєю командою / сценарієм як перший аргумент, і ви добре.

Цей сценарій також розміщений (і можливо оновлений) на Github .

#!/bin/bash
# Run as if it was called from cron, that is to say:
#  * with a modified environment
#  * with a specific shell, which may or may not be bash
#  * without an attached input terminal
#  * in a non-interactive shell

function usage(){
    echo "$0 - Run a script or a command as it would be in a cron job, then display its output"
    echo "Usage:"
    echo "   $0 [command | script]"
}

if [ "$1" == "-h" -o "$1" == "--help" ]; then
    usage
    exit 0
fi

if [ $(whoami) != "root" ]; then
    echo "Only root is supported at the moment"
    exit 1
fi

# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
    echo "Unable to find $cron_env"
    echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
    exit 0
fi

# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
   env_string="${env_string} $envi "
done

cmd_string=""
for arg in "$@"; do
    cmd_string="${cmd_string} \"${arg}\" "
done

# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"


# Let's route the output in a file
# and do not provide any input (so that the command is executed without an attached terminal)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" >"$so" 2>"$se" < /dev/null

echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"

0

Відповідь https://stackoverflow.com/a/2546509/5593430 показує, як отримати середовище cron і використовувати його для свого сценарію. Але майте на увазі, що середовище може відрізнятися залежно від файлу crontab, який ви використовуєте. Я створив три різні записи в cron, щоб врятувати середовище через env > log. Це результати на Amazon Linux 4.4.35-33.55.amzn1.x86_64.

1. Глобальний / etc / crontab з користувачем root

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PWD=/
LANG=en_US.UTF-8
SHLVL=1
HOME=/
LOGNAME=root
_=/bin/env

2. Crontab користувача root ( crontab -e)

SHELL=/bin/sh
USER=root
PATH=/usr/bin:/bin
PWD=/root
LANG=en_US.UTF-8
SHLVL=1
HOME=/root
LOGNAME=root
_=/usr/bin/env

3. Сценарій у /etc/cron.hourly/

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
_=/bin/env
PWD=/
LANG=en_US.UTF-8
SHLVL=3
HOME=/
LOGNAME=root

Найголовніше PATH, PWDі HOMEвідрізняються. Обов’язково встановіть їх у своїх сценаріях cron, щоб покладатися на стабільне середовище.


-8

Я не вірю, що існує; Єдиний спосіб, який я знаю, щоб перевірити роботу з крон - це налаштувати його на майбутнє хвилину чи дві, а потім чекати.


Ось чому я прошу імітувати
Хорхе Варгас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.