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

Скрипт Cron выполняется несколько раз

У нас есть сценарий, который используется для синхронизации некоторых каталогов с USB-накопителем. Он настроен на запуск один раз в день, но часто занимает больше времени.

Чтобы убедиться, что несколько копий сценария не запускаются одновременно, мы проверяем список процессов и, если наш сценарий присутствует, немедленно выходим.

#!/bin/bash

#check if we are already running
running=$(ps aux | /usr/bin/grep -i "usb_sync" | /usr/bin/grep -v grep | /usr/bin/grep -c bash)
echo "usb_sync $running" >/opt/local/backup/usb_sync_log
#If we are, the quit
if [ $running -gt 1 ] ; then
  exit 0
fi

Проблема в том, что эта проверка работает нормально при запуске через sudo и ручном вызове через интерфейс командной строки. Однако, когда он запускается через cron, он запускается независимо. Я пробовал несколько разных вариантов, но все они работают.

Это на FreeNAS 11.2.

Можно сделать намного проще. Создайте файл флага. В начале вашего скрипта можно использовать:

    ## Basic config
SCRIPTNAME=$(basename "$0")
RUNFILE="${SCRIPTNAME}.run"
# 25h in seconds adjust to your needs.
MAX_AGE=90000


    # check for running process
    if [ -f "$RUNFILE" ]; then
      echo "process still running - exit"
      if [ $(( $(date +%s) - $(date +%s --reference $RUNFILE) )) -gt ${MAX_AGE} ]; then
         rm $RUNFILE;
      else 
         exit
      fi
    fi
    touch $RUNFILE

<your code>

rm ${RUNFILE}

Содержимое исполняемого файла может быть PID запущенного процесса. Было бы легче проанализировать, есть ли запущенный процесс.

Вместо того

touch ${RUNFILE}

использовать

echo $$ >${RUNFILE}

А pid file - это общий подход к предотвращению многократного выполнения сценария. Его можно использовать так:

#!/bin/bash

PIDFILE=/home/vagrant/forever.pid
if [ -f $PIDFILE ]
then
  PID=$(cat $PIDFILE)
  ps -p $PID > /dev/null 2>&1
  if [ $? -eq 0 ]
  then
    echo "Process already running"
    exit 1
  else
    ## Process not found assume not running
    echo $$ > $PIDFILE
    if [ $? -ne 0 ]
    then
      echo "Could not create PID file"
      exit 1
    fi
  fi
else
  echo $$ > $PIDFILE
  if [ $? -ne 0 ]
  then
    echo "Could not create PID file"
    exit 1
  fi
fi

sleep 25d
rm $PIDFILE

куда sleep 25d это фактическая команда, которая должна быть выполнена. Рекомендую прочитать это Сообщение блога для подробного объяснения различных методов решения этой проблемы. Скрипт выше взят оттуда.

Следует проверить права доступа пользователя для выполнения сценария, указанные в файле cron. Текущий сценарий также может просто не определить, запущен ли сценарий уже из-за недостаточности прав доступа. В любом случае использование файла pid кажется лучшим и менее подверженным ошибкам решением этой проблемы.