У меня обычно есть несколько проблем с тем, как cron выполняет сценарии, так как они обычно не имеют моей настройки среды. Есть ли способ вызвать bash (?) Таким же образом, как это делает cron, чтобы я мог тестировать сценарии перед их установкой?
У меня обычно есть несколько проблем с тем, как cron выполняет сценарии, так как они обычно не имеют моей настройки среды. Есть ли способ вызвать bash (?) Таким же образом, как это делает cron, чтобы я мог тестировать сценарии перед их установкой?
Ответы:
Добавьте это в ваш crontab (временно):
* * * * * env > ~/cronenv
После запуска сделайте это:
env - `cat ~/cronenv` /bin/sh
Это предполагает, что ваш cron запускает / bin / sh, который используется по умолчанию независимо от оболочки пользователя по умолчанию.
env -
кошка ~ / cronenv` / бен / sh` должно быть написано , как хроны также? приведите пожалуйста пример
Cron предоставляет только эту среду по умолчанию:
HOME
домашний каталог пользователяLOGNAME
логин пользователяPATH=/usr/bin:/usr/sbin
SHELL=/usr/bin/sh
Если вам нужно больше, вы можете создать сценарий, в котором вы определяете свою среду перед таблицей планирования в crontab.
Пара подходов:
Экспортируйте cron env и поставьте его:
Добавить
* * * * * env > ~/cronenv
в ваш crontab, дайте ему один раз запустить, выключите его, затем запустите
env - `cat ~/cronenv` /bin/sh
И теперь вы находитесь в sh
сеансе, в котором есть среда cron
Принеси свое окружение в cron
Вы можете пропустить вышеупомянутое упражнение и просто сделать . ~/.profile
перед своей работой, например:
* * * * * . ~/.profile; your_command
Использовать экран
Вышеперечисленные два решения по-прежнему терпят неудачу в том, что они предоставляют среду, подключенную к запущенному сеансу X, с доступом к ним dbus
и т. Д. Например, в Ubuntu nmcli
(Network Manager) будет работать в двух вышеупомянутых подходах, но все равно не будет работать в cron.
* * * * * /usr/bin/screen -dm
Добавьте указанную выше строку в cron, дайте ей один раз поработать, снова выключите. Подключитесь к сеансу экрана (screen -r). Если вы проверяете, что сеанс экрана был создан (с ps
), имейте в виду, что они иногда в столицах (например ps | grep SCREEN
)
Теперь даже nmcli
и подобное не получится.
Вы можете запустить:
env - your_command arguments
Это запустит your_command с пустой средой.
env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command arguments
который, кажется, делает
В зависимости от оболочки аккаунта
sudo su
env -i /bin/sh
или
sudo su
env -i /bin/bash --noprofile --norc
От http://matthew.mceachen.us/blog/howto-simulate-the-cron-environment-1018.html
Отвечая шесть лет спустя: проблема несоответствия среды является одной из проблем, решаемых systemd
«таймерами» в качестве замены хрон. Независимо от того, запускаете ли вы «service» 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"
Так что уже есть больше шансов, что системный таймер найдет двоичный файл без лишних хлопот.
Недостаток системных таймеров - немного больше времени для их настройки. Сначала вы создаете файл «service», чтобы определить, что вы хотите запустить, и файл «timer», чтобы определить расписание его запуска и, наконец, «включить» таймер, чтобы активировать его.
Создайте задание cron, которое запускает env и перенаправляет stdout в файл. Используйте файл вместе с «env -», чтобы создать ту же среду, что и задание cron.
Не забывайте, что, поскольку родитель cron является init, он запускает программы без управляющего терминала. Вы можете смоделировать это с помощью такого инструмента:
По умолчанию cron
выполняет свои задания, используя то, о чем ваша система представляет sh
. Это может быть фактическим Борна оболочка или dash
, ash
, ksh
или bash
(или другой) слинковано в sh
(и , как следствие , работающем в режиме POSIX).
Лучше всего убедиться, что в ваших скриптах есть то, что им нужно, и предположить, что для них ничего не предусмотрено. Поэтому вы должны использовать полные спецификации каталогов и устанавливать такие переменные среды, как $PATH
вы.
0 0 * * 1 /path/to/executable >/dev/null 2>&1
затем в «исполняемом файле» я бы установил значения $PATH
и т. Д., А также использовал полные спецификации каталогов для ввода и вывода файлов и т. Д. Например:/path/to/do_something /another/path/input_file /another/path/to/output_file
Другой простой способ, который я нашел (но может быть подвержен ошибкам, я все еще тестирую), состоит в том, чтобы найти файлы профиля вашего пользователя перед вашей командой.
Редактирование скрипта /etc/cron.d/:
* * * * * user1 comand-that-needs-env-vars
Превратился бы в:
* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars
Грязный, но он сделал работу за меня. Есть ли способ симулировать логин? Просто команда, которую вы могли бы запустить? bash --login
не работал Похоже, это был бы лучший путь.
РЕДАКТИРОВАТЬ: Это, кажется, твердое решение: 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
Принятый ответ дает возможность запустить скрипт в среде, которую будет использовать cron. Как отмечали другие, это не единственный необходимый критерий для отладки заданий 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"
Ответ https://stackoverflow.com/a/2546509/5593430 показывает, как получить среду cron и использовать ее для своего сценария. Но имейте в виду, что среда может отличаться в зависимости от используемого файла crontab. Я создал три разные записи cron, чтобы сохранить среду через env > log
. Это результаты на Amazon Linux 4.4.35-33.55.amzn1.x86_64.
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
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
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, чтобы они полагались на стабильную среду.
Я не верю, что есть; единственный способ проверить работу cron - это настроить ее на запуск через минуту или две, а затем подождать.