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

GNU bash, версия 1.14.7 (1)

У меня есть script называется "abc.sh" Я должен проверить это только с abc.sh script... внутри него я написал следующее утверждение

status=`ps -efww | grep -w "abc.sh" | grep -v grep | grep -v $$ | awk '{ print $2 }'`
if [ ! -z "$status" ]; then
        echo "[`date`] : abc.sh : Process is already running"
        exit 1;
fi

Я знаю это неправильно, потому что каждый раз, когда он выходит, поскольку он нашел свой собственный процесс в 'ps' как его решить? как я могу проверить, что script уже запущен или не только from that script?

Ответы

Ответ 1

Более простой способ проверить уже выполненный процесс - это команда pidof.

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi

В качестве альтернативы создайте файл script для создания PID файла при его выполнении. Затем это простое упражнение по проверке наличия файла PID для определения того, запущен ли процесс.

#!/bin/bash
# abc.sh

mypidfile=/var/run/abc.sh.pid

# Could add check for existence of mypidfile here if interlock is
# needed in the shell script itself.

# Ensure PID file is removed on program exit.
trap "rm -f -- '$mypidfile'" EXIT

# Create a file with current PID to indicate that process is running.
echo $$ > "$mypidfile"

...

Update: Теперь вопрос изменился на проверку с самого script. В этом случае мы ожидаем всегда видеть хотя бы один abc.sh. Если имеется более одного abc.sh, мы знаем, что процесс все еще работает. Я все же предлагаю использовать команду pidof, которая вернет 2 PID, если процесс уже запущен. Вы можете использовать grep для фильтрации текущего PID, петли в оболочке или даже возврата к простому подсчету PID с помощью wc для обнаружения нескольких процессов.

Вот пример:

#!/bin/bash

for pid in $(pidof -x abc.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : abc.sh : Process is already running with PID $pid"
        exit 1
    fi
done

Ответ 2

Мне нужен метод "pidof", вот трюк:

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi

Где параметр -o %PPID указывает опустить pid вызывающей оболочки или оболочки script. Больше информации на странице pidof.

Ответ 3

Вот один трюк, который вы увидите в разных местах:

status=`ps -efww | grep -w "[a]bc.sh" | awk -vpid=$$ '$2 != pid { print $2 }'`
if [ ! -z "$status" ]; then
    echo "[`date`] : abc.sh : Process is already running"
    exit 1;
fi

Скобки вокруг [a] (или выбрать другую букву) не позволяют grep найти себя. Это делает бит grep -v grep ненужным. Я также удалил grep -v $$ и исправил часть awk, чтобы выполнить ту же самую вещь.

Ответ 4

Кто-то, пожалуйста, застрелите меня, если я ошибаюсь здесь.

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

#!/bin/sh
lockdir=/tmp/AXgqg0lsoeykp9L9NZjIuaqvu7ANILL4foeqzpJcTs3YkwtiJ0
mkdir $lockdir  || {
    echo "lock directory exists. exiting"
    exit 1
}
# take pains to remove lock directory when script terminates
trap "rmdir $lockdir" EXIT INT KILL TERM

# rest of script here

Ответ 5

Вот как я это делаю в bash script:

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi

Это позволяет мне использовать этот фрагмент для любого bash script. Мне нужно было grep bash, потому что при использовании с cron он создает другой процесс, который выполняет его с помощью/bin/sh.

Ответ 6

Используйте команду PS немного иначе, чтобы игнорировать дочерний процесс:

ps -eaf | grep -v grep | grep $PROCESS | grep -v $$

Ответ 7

Я нахожу ответ от @Austin Phillips точным. Одно небольшое улучшение, которое я хотел бы сделать, это добавить -o (чтобы игнорировать pid самого скрипта) и сопоставить скрипт с базовым именем (то есть тот же код можно вставить в любой скрипт):

if pidof -x "'basename $0'" -o $$ >/dev/null; then
    echo "Process already running"
fi

Ответ 8

Я создаю временный файл во время выполнения.

Вот как я это делаю:

#!/bin/sh
# check if lock file exists
if [ -e /tmp/script.lock ]; then
  echo "script is already running"
else
# create a lock file
  touch /tmp/script.lock
  echo "run script..."
#remove lock file
 rm /tmp/script.lock
fi

Ответ 9

Я обнаружил, что использование обратных галочек для записи вывода команды в переменную, к сожалению, приводит к получению слишком большого числа результатов ps aux, например, для одного запущенного экземпляра abc.sh:

ps aux | grep -w "abc.sh" | grep -v grep | wc -l

возвращает "1". Тем не менее,

count='ps aux | grep -w "abc.sh" | grep -v grep | wc -l'
echo $count

возвращает "2"

Похоже, что использование конструкции backtick как-то временно создает другой процесс. Может быть причина, по которой автор темы не может сделать эту работу. Просто нужно уменьшить значение переменной $ count.

Ответ 10

pidof не работал для меня, поэтому я искал еще немного и наткнулся на pgrep

for pid in $(pgrep -f my_script.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : my_script.sh : Process is already running with PID $pid"
        exit 1
    else
      echo "Running with PID $pid"
    fi  
done

Взято частично из ответов выше и https://askubuntu.com/a/803106/802276

Ответ 11

Я не хотел жестко кодировать abc.sh в чеке, поэтому я использовал следующее:

MY_SCRIPT_NAME='basename "$0"'
if pidof -o %PPID -x $MY_SCRIPT_NAME > /dev/null; then
    echo "$MY_SCRIPT_NAME already running; exiting"
    exit 1
fi

Ответ 12

Это компактный и универсальный

# exit if another instance of this script is running
for pid in $(pidof -x 'basename $0'); do
   [ $pid != $$ ] && { exit 1; }
done