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

Вот рекурсивная функция, которая использует стек, в котором мы храним номера разделов в порядке возрастания. Это достаточно быстро и очень интуитивно понятно.

# get the partitions of an integer

Stack = []
def Partitions(remainder, start_number = 1):
    if remainder == 0:
        print(" + ".join(Stack))
    else:
        for nb_to_add in range(start_number, remainder+1):
            Stack.append(str(nb_to_add))
            Partitions(remainder - nb_to_add, nb_to_add)
            Stack.pop()

Когда стек заполнен (сумма элементов стека соответствует числу, которое мы хотим разделить), мы печатаем его, удаляем его последнее значение и проверяем следующее возможное значение, которое будет сохранено в стек. Когда все следующие значения были проверены, мы снова выталкиваем последнее значение стека и возвращаемся к последней вызывающей функции. Вот пример выходных данных (с 8):

Partitions(8)
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1 + 1 + 2
1 + 1 + 1 + 1 + 1 + 3
1 + 1 + 1 + 1 + 2 + 2
1 + 1 + 1 + 1 + 4
1 + 1 + 1 + 2 + 3
1 + 1 + 1 + 5
1 + 1 + 2 + 2 + 2
1 + 1 + 2 + 4
1 + 1 + 3 + 3
1 + 1 + 6
1 + 2 + 2 + 3
1 + 2 + 5
1 + 3 + 4
1 + 7
2 + 2 + 2 + 2
2 + 2 + 4
2 + 3 + 3
2 + 6
3 + 5
4 + 4
8

Структура рекурсивной функции проста для понимания и проиллюстрирована ниже (для целого числа 31):

remainder соответствует значению оставшегося числа, которое мы хотим разделить (31 и 21 в приведенном выше примере). start_number соответствует первому номеру раздела, его значение по умолчанию равно единице (1 и 5 в примере выше).

Если бы мы хотели вернуть результат в список и получить количество разделов, мы могли бы сделать это:

def Partitions2_main(nb):
    global counter, PartitionList, Stack
    counter, PartitionList, Stack = 0, [], []
    Partitions2(nb)
    return PartitionList, counter

def Partitions2(remainder, start_number = 1):
    global counter, PartitionList, Stack
    if remainder == 0:
        PartitionList.append(list(Stack))
        counter += 1
    else:
        for nb_to_add in range(start_number, remainder+1):
            Stack.append(nb_to_add)
            Partitions2(remainder - nb_to_add, nb_to_add)
            Stack.pop()

Наконец, большое преимущество функции Partitions, показанной выше, состоит в том, что она очень легко адаптируется, чтобы найти все композиции натурального числа (две композиции могут иметь одинаковый набор чисел, но порядок в этом случае различен): нам просто нужно сбросить переменную start_number и установить ее в 1 в for петля.

# get the compositions of an integer

Stack = []
def Compositions(remainder):
    if remainder == 0:
        print(" + ".join(Stack))
    else:
        for nb_to_add in range(1, remainder+1):
            Stack.append(str(nb_to_add))
            Compositions(remainder - nb_to_add)
            Stack.pop()

Пример вывода:

Compositions(4)
1 + 1 + 1 + 1
1 + 1 + 2
1 + 2 + 1
1 + 3
2 + 1 + 1
2 + 2
3 + 1
4

10
задан Ryan Detzel 29 May 2009 в 17:04
поделиться

7 ответов

Вместо файлов pid, если у вашего сценария есть однозначно идентифицируемое имя, вы можете сделать что-то вроде этого:

#!/bin/bash
COMMAND=$0
# exit if I am already running
RUNNING=`ps --no-headers -C${COMMAND} | wc -l`
if [ ${RUNNING} -gt 1 ]; then
  echo "Previous ${COMMAND} is still running."
  exit 1
fi
... rest of script ...
3
ответ дан 3 December 2019 в 14:35
поделиться

Вы можете использовать pidof -x , если вы знаете имя процесса, или kill -0 , если вы знаете PID.

Пример:

if pidof -x vim > /dev/null
then
    echo "Vim already running"
    exit 1
fi
13
ответ дан 3 December 2019 в 14:35
поделиться

Почему бы не установить файл блокировки?

Что-то вроде

yourapp.lock

Просто удалите его, когда процесс будет завершен, и проверьте его перед запуском .

Это можно сделать с помощью

if [ -f yourapp.lock ]; then
echo "The process is already launched, please wait..."
fi
5
ответ дан 3 December 2019 в 14:35
поделиться
pgrep -f yourscript >/dev/null && exit
3
ответ дан 3 December 2019 в 14:35
поделиться

Используйте этот сценарий:

FILE="/tmp/my_file"
if [ -f "$FILE" ]; then
   echo "Still running"
   exit
fi
trap EXIT "rm -f $FILE"
touch $FILE

...script here...

Этот сценарий создаст файл и удалит его при выходе.

1
ответ дан 3 December 2019 в 14:35
поделиться

Чтобы расширить то, что говорит @bgy, безопасный атомарный способ создать файл блокировки, если он еще не существует, и потерпеть неудачу, если его нет, - это чтобы создать временный файл, а затем жестко связать его со стандартным файлом блокировки. Это защищает от другого процесса, создающего файл между вашим тестированием и созданием.

Вот код файла блокировки из моего почасового сценария резервного копирования:

echo $$ > /tmp/lock.$$
if ! ln /tmp/lock.$$ /tmp/lock ; then 
        echo "previous backup in process"
        rm /tmp/lock.$$
        exit
fi

Не забудьте удалить как файл блокировки, так и временный файл. файл, когда вы закончите, даже если вы выйдете раньше из-за ошибки.

1
ответ дан 3 December 2019 в 14:35
поделиться

For a method that does not suffer from parsing bugs and race conditions, check out:

2
ответ дан 3 December 2019 в 14:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: