Вам не нужен expr для этого. Можно использовать конструкции оболочки ${VAR#PATTERN}
который расширяется до $VAR
с самым коротким префиксом, который соответствует указанному неизолированному шаблону, ${VAR##PATTERN}
который разделяет самый длинный префикс, и ${VAR%PATTERN}
и ${VAR%%PATTERN}
которые разделяют суффиксы.
text='A234321=http://www.example.com/wibble'
protocol=${text%%://*}
url=${protocol##*[!a-z]}://${text#*://}
Почти как ответ nsg: используйте каталог блокировки. Создание каталога является атомарным в соответствии с Linux и Unix и *BSD и много других Ose.
if mkdir $LOCKDIR
then
# Do important, exclusive stuff
if rmdir $LOCKDIR
then
echo "Victory is mine"
else
echo "Could not remove lock dir" >&2
fi
else
# Handle error condition
...
fi
Вы можете поместить PID блокировки sh в файл в каталоге блокировки для отладки целей, но не попадаете в прерывание размышления, что можно проверить, что PID, чтобы видеть, выполняется ли процесс блокировки все еще. Много условий состязания ложится тот путь.
Это может быть слишком упрощенно, исправьте меня, если я неправ. Не простое ps
достаточно?
#!/bin/bash
me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;
# do stuff below this comment
grep -v $$
. реальные примеры: старый - 14532, новый - 1453, старый - 28858, новый - 858.
– Naktibalda
22.02.2018, 13:30
grep -wv "^$$"
(см. редактирование).
– terdon♦
22.02.2018, 14:38
Я использовал бы файл блокировки, как упомянуто Marco
#!/bin/bash
# Exit if /tmp/lock.file exists
[ -f /tmp/lock.file ] && exit
# Create lock file, sleep 1 sec and verify lock
echo $$ > /tmp/lock.file
sleep 1
[ "x$(cat /tmp/lock.file)" == "x"$$ ] || exit
# Do stuff
sleep 60
# Remove lock file
rm /tmp/lock.file
lsof $0
не плохо, также?
– Tobias Kienzler
18.09.2012, 14:34
$$
в файле блокировки. Затем sleep
для короткого интервала и читают его назад. Если PID является все еще Вашим, Вы успешно получили блокировку. Не нуждается в абсолютно никаких дополнительных инструментах.
– manatwork
18.09.2012, 14:41
Если Вы хотите удостовериться, что только один экземпляр Вашего сценария работает, смотрят на:
Заблокируйте свой сценарий (против выполненной параллели)
Иначе можно проверить ps
или вызовите lsof <full-path-of-your-script>
, так как я не назвал бы их дополнительными инструментами.
Дополнение:
на самом деле я думал о выполнении его как это:
for LINE in `lsof -c <your_script> -F p`; do
if [ $$ -gt ${LINE#?} ] ; then
echo "'$0' is already running" 1>&2
exit 1;
fi
done
это гарантирует что только процесс с самым низким pid
продолжает работать даже если Вы ветвление-и-должностное-лицо несколько экземпляров <your_script>
одновременно.
[[(lsof $0 | wc -l) > 2]] && exit
мог бы на самом деле быть достаточно, или это также подвержено условиям состязания? операция в секунду
– Tobias Kienzler
18.09.2012, 14:30
Чтобы добавить в Ответ Ответ Bruce Ediger , и вдохновлен Этот ответ Этот ответ , вы также должны добавить больше умных для очистки для защиты от скрипта:
#Remove the lock directory
function cleanup {
if rmdir $LOCKDIR; then
echo "Finished"
else
echo "Failed to remove lock directory '$LOCKDIR'"
exit 1
fi
}
if mkdir $LOCKDIR; then
#Ensure that if we "grabbed a lock", we release it
#Works for SIGTERM and SIGINT(Ctrl-C)
trap "cleanup" EXIT
echo "Acquired lock, running"
# Processing starts here
else
echo "Could not create lock directory '$LOCKDIR'"
exit 1
fi
Хотя вы просили найти решение без дополнительных инструментов, это мой любимый способ использования flock
:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
Это взято из раздела примеров man flock
, в котором дополнительно объясняется:
Т это полезный шаблонный код для сценариев оболочки. Поместите его в начало сценария оболочки, который вы хотите заблокировать, и он автоматически заблокируется при первом запуске. Если env var $ FLOCKER не настроен на запускаемый сценарий оболочки, выполните flock и захватите исключительную неблокирующую блокировку (используя сам сценарий в качестве файла блокировки) перед повторным запуском с правильными аргументами. Он также устанавливает правильное значение переменной env FLOCKER, чтобы она больше не запускалась.
На что следует обратить внимание:
flock
, пример сценария завершается с ошибкой, если он не может быть найден Это модифицированная версия Ответа Ансельмо . Идея состоит в том, чтобы создать файловый дескриптор только для чтения с помощью самого сценария bash и использовать flock
для обработки блокировки.
script=`realpath $0` # get absolute path to the script itself
exec 6< "$script" # open bash script using file descriptor 6
flock -n 6 || { echo "ERROR: script is already running" && exit 1; } # lock file descriptor 6 OR show error message if script is already running
echo "Run your single instance code here"
Основное отличие от всех других ответов заключается в том, что этот код не изменяет файловую систему, занимает очень мало места и не нуждается в какой-либо очистке, поскольку дескриптор файла закрывается, как только сценарий завершается, независимо от состояния выхода.. Таким образом, не имеет значения, будет ли сценарий неудачным или успешным.
Мой код тебе
#!/bin/bash
script_file="$(/bin/readlink -f $0)"
lock_file=${script_file////_}
function executing {
echo "'${script_file}' already executing"
exit 1
}
(
flock -n 9 || executing
sleep 10
) 9> /var/lock/${lock_file}
На основе man flock
, только улучшение:
executing
Там, где я поставил здесь sleep 10
, можно поставить все основные скрипты.
Я использую cksum для проверки того, что мой скрипт действительно работает в одном экземпляре, даже если я меняю имя файла и путь к файлу .
Я не использую файл ловушки и блокировки, потому что, если мой сервер внезапно выйдет из строя,Мне нужно вручную удалить файл блокировки после запуска сервера.
Примечание:#!/bin/bash в первой строке требуется для grep ps
#!/bin/bash
checkinstance(){
nprog=0
mysum=$(cksum $0|awk '{print $1}')
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(cksum /proc/$i/cwd/$cmd|awk '{print $1}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
Или вы можете жестко запрограммировать cksum внутри вашего скрипта, так что вы больше не будете беспокоиться, если захотите изменить имя файла, путь или содержимое вашего скрипта .
#!/bin/bash
mysum=1174212411
checkinstance(){
nprog=0
for i in `ps -ef |grep /bin/bash|awk '{print $2}'`;do
proc=$(ls -lha /proc/$i/exe 2> /dev/null|grep bash)
if [[ $? -eq 0 ]];then
cmd=$(strings /proc/$i/cmdline|grep -v bash)
if [[ $? -eq 0 ]];then
fsum=$(grep mysum /proc/$i/cwd/$cmd|head -1|awk -F= '{print $2}')
if [[ $mysum -eq $fsum ]];then
nprog=$(($nprog+1))
fi
fi
fi
done
if [[ $nprog -gt 1 ]];then
echo $0 is already running.
exit
fi
}
checkinstance
#--- run your script bellow
echo pass
while true;do sleep 1000;done
Этот удобный пакет делает то, что вы ищете.
https://github.com/krezreb/singleton
после установки просто добавьте к команде префиксsingleton LOCKNAME
напр.singleton LOCKNAME PROGRAM ARGS...
Самый простой сценарий с одним вкладышем вместо написания сложных операторов PID или блокировки
flock -xn LOCKFILE.lck -c SCRIPT.SH
где x обозначает эксклюзивную блокировку а n обозначает не блокировку -, которая терпит неудачу, а не ожидает освобождения блокировки. c запускает сценарий, который вы хотите запустить.
mkdir
не является атомарным на NFS (который не имеет место для меня, но я предполагаю, что нужно упомянуть, что, если верный), – Tobias Kienzler 18.09.2012, 16:08/tmp
который обычно является не совместно использованным NFS, так, чтобы был прекрасен. – Tobias Kienzler 19.09.2012, 11:33rm -rf
удалить каталог блокировки.rmdir
перестанет работать, если кому-то (не обязательно Вы) удалось добавить файл к каталогу. – chepner 22.09.2012, 07:32