Я реализовал синтаксический анализатор с рекурсивным спуском в Java в Синтаксический анализатор MathEclipse проект. Это могло также использоваться в в качестве модуль Google Web Toolkit
Если сценарий одинаков для всех пользователей, вы можете использовать подход файл блокировки
. Если вы получили блокировку, продолжайте, иначе покажите сообщение и выйдите.
В качестве примера:
[Terminal #1] $ lockfile -r 0 /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] lockfile: Sorry, giving up on "/tmp/the.lock"
[Terminal #1] $ rm -f /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] $
После того, как /tmp/the.lock
будет получен, ваш скрипт будет единственным, у кого есть доступ к исполнение. Когда вы закончите, просто снимите замок. В форме сценария это может выглядеть так:
#!/bin/bash
lockfile -r 0 /tmp/the.lock || exit 1
# Do stuff here
rm -f /tmp/the.lock
из вашего скрипта:
ps -ef | grep $0 | grep $(whoami)
Я не уверен, что существует надежное однострочное решение, так что вы можете в конечном итоге свернуть свой собственный.
Lockfiles несовершенны, но в меньшей степени, чем при использовании 'ps | grep | grep -v 'pipelines.
Сказав это, вы могли бы подумать о сохранении контроля над процессом отдельно от вашего скрипта - имейте стартовый скрипт. Или, по крайней мере, разложите его на функции, хранящиеся в отдельном файле, так что в вызывающем скрипте вы можете иметь:
. my_script_control.ksh
# Function exits if cannot start due to lockfile or prior running instance.
my_start_me_up lockfile_name;
trap "rm -f $lockfile_name; exit" 0 2 3 15
в каждом скрипте, которому нужна управляющая логика. Ловушка гарантирует, что файл блокировки будет удален при выходе вызывающего объекта, поэтому вам не нужно кодировать это в каждой точке выхода в скрипте.
Использование отдельного управляющего скрипта означает, что вы можете проверить работоспособность на крайние случаи:
удалите устаревшие файлы журнала, убедитесь, что файл блокировки правильно связан с
текущий запущенный экземпляр сценария, дать возможность убить запущенный процесс и так далее.
Это также означает, что у вас больше шансов успешно использовать команду grep для вывода ps
.
Команда ps-grep может использоваться для проверки того, что с файлом блокировки связан запущенный процесс.
Возможно, вы могли бы назвать свои файлы блокировок каким-либо образом, чтобы включить информацию о процессе:
user, pid и т. д., которые могут использоваться при последующем вызове сценария, чтобы решить, будет ли процесс
файл блокировки все еще существует.
Я нашел довольно простой способ справиться с «одной копией скрипта на систему». Однако это не позволяет мне запускать несколько копий скрипта из многих учетных записей (то есть в стандартном Linux).
Решение:
В начале скрипта я дал:
pidof -s -o '%PPID' -x $( basename $0 ) > /dev/null 2>&1 && exit
Очевидно pidof отлично работает в том смысле, что:
ps -C ...
grep -v grep
(или что-то подобное) И он не полагается на файлы блокировки, что для меня является большой победой, потому что ретрансляция на них означает, что вам нужно добавить обработку устаревших файлов блокировки - что на самом деле не сложно, но если этого можно избежать - почему бы и нет?
Что касается проверки с «одной копией скрипта на каждого работающего пользователя», я написал это, но меня это не слишком устраивает:
(
pidof -s -o '%PPID' -x $( basename $0 ) | tr ' ' '\n'
ps xo pid= | tr -cd '[0-9\n]'
) | sort | uniq -d
, а затем я проверяю его вывод - если он пуст - нет копий скрипта от того же пользователя.
Advisory locking has been used for ages and can be used in bash scripts. Я предпочитаю простой flock
(из util-linux[-ng]
), а не lockfile
(из procmail
). И всегда помните о ловушке на выходе (sigspec == EXIT
или 0
, ловушка специфических сигналов лишняя) в этих скриптах.
В 2009 году я выпустил свой блокируемый boilerplate скрипта (изначально доступный на моей вики-странице, теперь доступный как gist). Преобразование этого скрипта в одноэтапный - это тривиально. Используя его, вы также можете легко писать скрипты для других сценариев, требующих некоторой блокировки или синхронизации.
Вот упомянутая шаблонная версия для вашего удобства.
#!/bin/bash
# SPDX-License-Identifier: MIT
## Copyright (C) 2009 Przemyslaw Pawelczyk <przemoc@gmail.com>
##
## This script is licensed under the terms of the MIT license.
## https://opensource.org/licenses/MIT
#
# Lockable script boilerplate
### HEADER ###
LOCKFILE="/var/lock/`basename $0`"
LOCKFD=99
# PRIVATE
_lock() { flock -$1 $LOCKFD; }
_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; }
_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; }
# ON START
_prepare_locking
# PUBLIC
exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail
exlock() { _lock x; } # obtain an exclusive lock
shlock() { _lock s; } # obtain a shared lock
unlock() { _lock u; } # drop a lock
### BEGIN OF SCRIPT ###
# Simplest example is avoiding running multiple instances of script.
exlock_now || exit 1
# Remember! Lock file is removed when one of the scripts exits and it is
# the only script holding the lock or lock is not acquired at all.
В дистрибутивах Ubuntu / Debian есть инструмент start-stop-daemon
, который предназначен для той же цели, которую вы описываете. См. Также /etc/init.d/skeleton , чтобы узнать, как он используется при написании сценариев запуска / остановки.
- Ной