Назад | Перейти на главную страницу

Сценарий Bash запускается вручную, но не работает на crontab

Я новичок в написании сценариев оболочки. Я написал сценарий оболочки для инкрементного резервного копирования базы данных MySQL. Сценарий имеет исполняемый формат и успешно работает при выполнении вручную, но не работает при выполнении через crontab.
Запись в crontab выглядит так: * / 1 * * * * /home/db-backup/mysqlbackup.sh
Ниже приведен код сценария оболочки -

 #!/bin/sh
MyUSER="root"       # USERNAME
MyPASS="password"         # PASSWORD
MyHOST="localhost"  # Hostname
Password="" #Linux Password

MYSQL="$(which mysql)"
if [ -z "$MYSQL" ]; then
echo "Error: MYSQL not found"
exit 1
fi
MYSQLADMIN="$(which mysqladmin)"
if [ -z "$MYSQLADMIN" ]; then
    echo "Error: MYSQLADMIN not found"
    exit 1
fi
CHOWN="$(which chown)"
if [ -z "$CHOWN" ]; then
    echo "Error: CHOWN not found"
    exit 1
fi
CHMOD="$(which chmod)"
if [ -z "$CHMOD" ]; then
    echo "Error: CHMOD not found"
    exit 1
fi

GZIP="$(which gzip)"
if [ -z "$GZIP" ]; then
    echo "Error: GZIP not found"
    exit 1
fi
CP="$(which cp)"
if [ -z "$CP" ]; then
    echo "Error: CP not found"
    exit 1
fi
MV="$(which mv)"
if [ -z "$MV" ]; then
    echo "Error: MV not found"
    exit 1
fi
RM="$(which rm)"
if [ -z "$RM" ]; then
    echo "Error: RM not found"
    exit 1
fi
RSYNC="$(which rsync)"
if [ -z "$RSYNC" ]; then
    echo "Error: RSYNC not found"
    exit 1
fi

MYSQLBINLOG="$(which mysqlbinlog)"
if [ -z "$MYSQLBINLOG" ]; then
    echo "Error: MYSQLBINLOG not found"
    exit 1
fi
# Get data in dd-mm-yyyy format
NOW="$(date +"%d-%m-%Y-%T")"

DEST="/home/db-backup"
mkdir $DEST/Increment_backup.$NOW
LATEST=$DEST/Increment_backup.$NOW
$MYSQLADMIN -u$MyUSER -p$MyPASS flush-logs
newestlog=`ls -d /usr/local/mysql/data/mysql-bin.?????? | sed 's/^.*\.//' | sort -g | tail -n 1`
echo $newestlog
for file in `ls /usr/local/mysql/data/mysql-bin.??????`
do
        if [ "/usr/local/mysql/data/mysql-bin.$newestlog" != "$file" ]; then
     echo $file             
     $CP "$file" $LATEST         
        fi
done
for file1 in `ls $LATEST/mysql-bin.??????`
do
 $MYSQLBINLOG $file1>$file1.$NOW.sql 
 $GZIP -9 "$file1.$NOW.sql"     
 $RM "$file1"
done
$RSYNC -avz $LATEST /home/rsync-back

Сценарии, запускаемые из crontab, не всегда имеют те же переменные среды, которые вы обычно принимаете как должное ... Сделайте следующее:

+ Изменить

 #!/bin/sh

к

 #!/bin/sh -x

с -x вы можете попробовать установить PATH вручную и даже отключить / etc / profile, если ничего не помогает.

#!/bin/sh -x
PATH=/bin:/sbin:/usr/bin:/usr/sbin
/bin/sh /etc/profile

попробуйте экспортировать пути и переменные, в crontabs пути должны быть указаны, способ, которым вы выполняете, в порядке, есть много сообщений на StackO и serverfault, где вы можете найти ответ на эту проблему

Версия оболочки / bin / sh не любит конструкцию $ (...). Лучше всего сделать одно из следующих:
1. Измените строку shebang на #! / Bin / bash
2. Измените команду crontab на * / 1 * * * * / bin / bash /home/db-backup/mysqlbackup.sh
3. И 1, и 2.

Для быстрого устранения неполадок обильно посыпьте свой сценарий эхом в выходной файл. Как поставить одну вверху:

#!/bin/bash
LOGFILE=/tmp/myoutput.log
echo "Starting" > $LOGFILE

и так далее. Затем вы можете посмотреть выходной файл после того, как сценарий должен был запуститься, и, возможно, увидеть, где он не работает. Если вывода вообще нет, возможно, он даже не работает, что мы еще не определили. Тогда вы сможете продолжить устранение неполадок.

Необходимые переменные среды, вероятно, не будут установлены при запуске скрипта из cron. Пытаться:

*/1 * * * * . /etc/profile; /home/db-backup/mysqlbackup.sh >>/tmp/mysqlbackup.log 2>&1

Это означает, что сначала настройте среду, запустив сценарий профиля по умолчанию перед фактическим резервным копированием. Дополнительно в конце есть перенаправление STDOUT и STDERR в файл журнала.

Найдите / var / log / cron или аналогичный. В зависимости от вашего вкуса * nix журнал также может находиться в ... / messages или ... / syslog. Искать cronв /etc/syslog.conf точный конфиг.

Надеюсь, это поможет :-)

Краткое решение: комментарий директивы HOME = / в вашем файле / etc / crontab

Теперь объяснение:

Я нашел эту тему, потому что мой сценарий резервного копирования mysql, очищающий bin-logs, отлично работал в интерактивном режиме, но не работал, когда cron. Но случилось так, что моя установка немного отличалась от установки Рудры, поэтому основная причина и решение тоже, но все же позвольте мне опубликовать это здесь для других с той же настройкой, что и у меня.

Хорошо, мое отличие от настройки Rudra в том, что я не передаю имя пользователя и пароль mysqladmin в скрипте. Вместо этого я настраиваю, как предложено в «6.1.2.1. Руководство для конечных пользователей по защите паролем »документации MySQL (http://dev.mysql.com/doc/refman/5.5/en/password-security-user.html ), т.е. в разделе [client] файла ~ / .my.cnf root.

Linux разрешает ~ в значения переменной окружения HOME. cron daemon (согласно man 5 crontab) «Некоторые переменные среды устанавливаются автоматически демоном cron (8). SHELL устанавливается в / bin / sh, а LOGNAME и HOME устанавливаются из строки / etc / passwd владельца crontab. HOME и SHELL могут быть отменены настройками в crontab »

Итак, с такой настройкой mysqladmin flush-logs должен работать нормально, без передачи пароля в качестве параметра командной строки, но это НЕ сработало. Причина этого заключалась в том, что (по любой причине) файл / etc / crontab по умолчанию (по крайней мере, в CenOS 6.2) имеет директиву HOME = /, перезаписывающую одну настройку, как описано в man.

Так что прокомментируйте его в своем / etc / crontab и убедитесь, что это вам поможет!

Ура, Роман.

У меня была такая же проблема с crontab в AIX 7.1.

Для этого я заменил команду /bin/sh с профильной оболочкой. Также в командной оболочке file.sh добавлено . ~/.profile в первой строке. После этого команда заработала нормально.

Это строка в crontab, которую я использовал:

mm hh * * * d . ~/.profile;/Directory/Command.sh > /LOG/logfile_command.log.`date | awk '{print $3$2$6}'` 2>&1

где мм: минуты, чч: час, д: день (0-6)

Каждый раз, когда вы используете запрос базы данных в скрипте, вам необходимо экспортировать путь. Ниже приводится экспорт базы данных Oracle:

ORACLE_HOME=/u01/app/oracle/product/11.2.0/db_1
LD_LIBRARY_PATH=$ORACLE_HOME/lib
PATH=$ORACLE_HOME/bin:$PATH

export PATH
export ORACLE_HOME
export ORACLE_SID
export LD_LIBRARY_PATH