
Я пытаюсь запустить скрипт, хранящийся в моем домашнем каталоге, через crontab, но он не работает. Журнал CRON просто говорит это каждый раз, когда он запускается:
Sep 3 18:30:01 backup CRON[6778]: (root) CMD (/home/hannes/script > /tmp/yc.log)
Sep 3 18:30:01 backup CRON[6777]: (CRON) info (No MTA installed, discarding output)
Кронтаб:
*/1 * * * * /home/hannes/script > /tmp/yc.log
Если я попробую добавить расширение файла .sh, это ничего не изменит. Файл yc.log останется пустым.
Вот скрипт, который я пытаюсь выполнить (работает нормально, если запустить его вручную):
#!/bin/sh
cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server
zip -r mnt/backup-nas/01/1.19_Test.`date +%d.%m.%Y_%H.%M.%S`.zip mnt/backup-nas/01/temp/server
rm -r mnt/backup-nas/01/temp/server
Любая помощь приветствуется! :)
решение1
Ваш сценарийявляетсяна самом деле работает... но где-то выдает ошибку. И поскольку вы не захватываете stderr
вывод, stderr отправляется cron
пользователю, который запускает скрипт локально. (И тоже падает)
Основная причина в следующем: ваш скрипт перенаправляет только stdout
в файлы. Однако множество неудачных скриптов и программ используют stderr
для вывода сообщений об ошибках. Вам нужно отловить это, добавив 2>&1
в конец вашей командной строки, которая cron
выполняется, что также будет захватывать stderr
и регистрировать ошибки в вашем файле.
Поскольку вы не перехватывали его ранее, stderr доставлялся по почте root
, но поскольку у вас нет локального MTA (Mail Transfer Agent, он же сервер Local Mail Transport Protocol (LMTP)) для локальной доставки, вы получили эти ошибки cron. С перехватом stderr
вы теперь увидите ошибки и то, почему ваш скрипт(ы) не запустился(лись) должным образом.
После того, как в ваших журналах появятся сообщения об ошибках, вы можете продолжить отладку скрипта, чтобы определить, что нужно сделать, чтобы «исправить» ситуацию.
решение2
Итак, было несколько проблем. Во-первых, я забыл добавить 2>&1
конец /home/hannes/script > /tmp/yc.log
, чтобы журнал действительно сохранился. А во-вторых, у меня была опечатка в скрипте, где я забыл первый слеш во всех путях. Это перешло от этого home/hannes/...
к этому /home/hannes/...
. Надеюсь, это поможет другим людям, у которых возникла похожая проблема, и спасибо всем, кто ответил :)
решение3
Принятый ответ правильный и охватывает поставленный вопрос. Однако информация, предоставленная в вопросе, указывает на не связанную потенциальную проблему с этим скриптом, о которой, как я считаю, важно предупредить OP, и правильное объяснение этого слишком длинно для комментария, поэтому я добавляю ответ специально, чтобы охватить это.
Помимо проблемы с ведением журнала, в вашей схеме также есть потенциально неприятное состояние гонки. Поскольку скрипт всегда использует один и тот же каталог для размещения файлов, подлежащих архивации, если одновременно запускается несколько экземпляров скрипта, то первый запуск, скорее всего, удалит файлы, над которыми в данный момент работают все последующие экземпляры, что приведет к дополнительным сбоям и, скорее всего, неполным архивам (потому что файлы исчезнут до того, как zip
их можно будет обработать).
Эту проблему можно решить двумя способами: либо сам скрипт должен использовать каталог для каждого вызова, либо следует использовать блокировку файлов для предотвращения одновременных запусков.
Первый подход намного проще, вы можете просто добавить дату в каталог, который вы используете. Это будет выглядеть примерно так (обратите внимание, что это также гарантирует, что вызов date
будет выполнен только один раз):
#!/bin/sh
now="$(date +%d.%m.%Y_%H.%M.%S)"
cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server/${now}
zip -r mnt/backup-nas/01/1.19_Test.${now}.zip mnt/backup-nas/01/temp/server/${now}
rm -r mnt/backup-nas/01/temp/server/${now}
Подход с блокировкой файлов немного сложнее, но, возможно, чище, поскольку он также гарантирует, что вы не сможете случайно завалить систему несколькими zip
командами, запущенными одновременно. Это включает в себя использование команды под названием flock
(часть пакета util-linux
в Ubuntu и Debian, который уже будет установлен), и выглядит примерно так (с комментариями, поясняющими, что происходит):
#!/bin/sh
# All of this gets run in a subshell so we can hold a file descriptor open
# for all the commands. We're using file descriptor 9 here, but any number
# higher than 2 will work.
(
# This flock command is what actually takes the lock. The lock itself
# persists until the file descriptor is closed when the subshell exits.
# The -x means it's an exclusive lock (so only one instance can hold it).
# The -w says to try for that many seconds before failing if something
# else is holding the lock (this is an important safety net to ensure you
# don’t get a long queue of these scripts waiting to run).
# The -n indicates which file descriptor to take the lock on.
flock -x -w 30 -n 9 || exit 1
cp -r -p mnt/main-nas/PATH-TO-FILE mnt/backup-nas/01/temp/server
zip -r mnt/backup-nas/01/1.19_Test.`date +%d.%m.%Y_%H.%M.%S`.zip mnt/backup-nas/01/temp/server
rm -r mnt/backup-nas/01/temp/server
# And this line closes the subshell, and also sets the path to be used for
# the lock file by opening it as file descriptor 9 for the subshell. /run
# is generally the place you want to put stuff like this, because it will
# get cleaned up automatically every time the system reboots.
) 9> /run/backup-nas.lock