Быстрый и грязный способ убедиться, что одновременно работает только один экземпляр сценария оболочки - PullRequest
166 голосов
/ 09 октября 2008

Какой быстрый и грязный способ убедиться, что в данный момент выполняется только один экземпляр сценария оболочки?

Ответы [ 39 ]

0 голосов
/ 13 мая 2014

Вот более элегантный, отказоустойчивый, быстрый & грязный метод, сочетающий ответы, представленные выше.

Использование

  1. include sh_lock_functions.sh
  2. init использует sh_lock_init
  3. блокировка с использованием sh_acquire_lock
  4. проверить блокировку, используя sh_check_lock
  5. разблокировать с помощью sh_remove_lock

Файл сценария

sh_lock_functions.sh

#!/bin/bash

function sh_lock_init {
    sh_lock_scriptName=$(basename $0)
    sh_lock_dir="/tmp/${sh_lock_scriptName}.lock" #lock directory
    sh_lock_file="${sh_lock_dir}/lockPid.txt" #lock file
}

function sh_acquire_lock {
    if mkdir $sh_lock_dir 2>/dev/null; then #check for lock
        echo "$sh_lock_scriptName lock acquired successfully.">&2
        touch $sh_lock_file
        echo $$ > $sh_lock_file # set current pid in lockFile
        return 0
    else
        touch $sh_lock_file
        read sh_lock_lastPID < $sh_lock_file
        if [ ! -z "$sh_lock_lastPID" -a -d /proc/$sh_lock_lastPID ]; then # if lastPID is not null and a process with that pid exists
            echo "$sh_lock_scriptName is already running.">&2
            return 1
        else
            echo "$sh_lock_scriptName stopped during execution, reacquiring lock.">&2
            echo $$ > $sh_lock_file # set current pid in lockFile
            return 2
        fi
    fi
    return 0
}

function sh_check_lock {
    [[ ! -f $sh_lock_file ]] && echo "$sh_lock_scriptName lock file removed.">&2 && return 1
    read sh_lock_lastPID < $sh_lock_file
    [[ $sh_lock_lastPID -ne $$ ]] && echo "$sh_lock_scriptName lock file pid has changed.">&2  && return 2
    echo "$sh_lock_scriptName lock still in place.">&2
    return 0
}

function sh_remove_lock {
    rm -r $sh_lock_dir
}

Пример использования

sh_lock_usage_example.sh

#!/bin/bash
. /path/to/sh_lock_functions.sh # load sh lock functions

sh_lock_init || exit $?

sh_acquire_lock
lockStatus=$?
[[ $lockStatus -eq 1 ]] && exit $lockStatus
[[ $lockStatus -eq 2 ]] && echo "lock is set, do some resume from crash procedures";

#monitoring example
cnt=0
while sh_check_lock # loop while lock is in place
do
    echo "$sh_scriptName running (pid $$)"
    sleep 1
    let cnt++
    [[ $cnt -gt 5 ]] && break
done

#remove lock when process finished
sh_remove_lock || exit $?

exit 0

Особенности

  • Использует комбинацию идентификатора файла, каталога и процесса для блокировки, чтобы убедиться, что процесс еще не запущен
  • Вы можете определить, остановился ли скрипт перед снятием блокировки (например, уничтожение процесса, завершение работы, ошибка и т. Д.)
  • Вы можете проверить файл блокировки и использовать его для запуска процесса, когда блокировка отсутствует
  • Подробно, выводит сообщения об ошибках для упрощения отладки
0 голосов
/ 09 октября 2008

Быстро и грязно?

#!/bin/sh

if [ -f sometempfile ]
  echo "Already running... will now terminate."
  exit
else
  touch sometempfile
fi

..do what you want here..

rm sometempfile
0 голосов
/ 23 сентября 2016

Это будет работать, если имя вашего скрипта уникально:

#!/bin/bash
if [ $(pgrep -c $(basename $0)) -gt 1 ]; then 
  echo $(basename $0) is already running
  exit 0
fi

Если имя скрипта не уникально, это работает в большинстве дистрибутивов Linux:

#!/bin/bash
exec 9>/tmp/my_lock_file
if ! flock -n 9  ; then
   echo "another instance of this script is already running";
   exit 1
fi

источник: http://mywiki.wooledge.org/BashFAQ/045

0 голосов
/ 02 августа 2016

Поздно к вечеринке, используя идею @Majal, это мой сценарий для запуска только одного экземпляра emacsclient GUI. С его помощью я могу установить ярлык для открытия или вернуться к тому же истощению. У меня есть другой скрипт для вызова emacsclient в терминалах, когда мне это нужно. Использование emacsclient здесь просто для того, чтобы показать работающий пример, можно выбрать что-то другое. Этот подход достаточно быстр и хорош для моих крошечных сценариев. Скажите, где это грязно:)

#!/bin/bash

# if [ $(pgrep -c $(basename $0)) -lt 2 ]; then # this works but requires script name to be unique
if [ $(pidof -x "$0"|wc -w ) -lt 3 ]; then
    echo -e "Starting $(basename $0)"
    emacsclient --alternate-editor="" -c "$@"
else
    echo -e "$0 is running already"
fi
0 голосов
/ 15 марта 2014

Посмотрите на FLOM (Free LOck Manager) http://sourceforge.net/projects/flom/: вы можете синхронизировать команды и / или сценарии, используя абстрактные ресурсы, которым не требуется блокировка файлов в файловой системе. Вы можете синхронизировать команды, выполняемые в разных системах, без NAS (Network Attached Storage), такого как сервер NFS (Network File System).

Используя простейший вариант использования, сериализовать «command1» и «command2» можно так же просто, как выполнить:

flom -- command1

и

flom -- command2

из двух разных сценариев оболочки.

0 голосов
/ 03 марта 2016

У меня есть простое решение на основе имени файла

#!/bin/bash

MY_FILENAME=`basename "$BASH_SOURCE"`

MY_PROCESS_COUNT=$(ps a -o pid,cmd | grep $MY_FILENAME | grep -v grep | grep -v $$ | wc -
l)

if [ $MY_PROCESS_COUNT -ne 0  ]; then
  echo found another process
  exit 0
if

# Follows the code to get the job done.
0 голосов
/ 30 ноября 2015
if [ 1 -ne $(/bin/fuser "$0" 2>/dev/null | wc -w) ]; then
    exit 1
fi
0 голосов
/ 29 июля 2015

почему мы не используем что-то вроде

pgrep -f $cmd || $cmd
0 голосов
/ 13 августа 2014

Попробуйте что-то вроде ниже,

ab=`ps -ef | grep -v grep | grep -wc processname`

Затем сопоставьте переменную с 1, используя цикл if.

...