추가 도구가 필요없는 솔루션이 선호됩니다.
ln -s my.pid .lock
잠금 ()이 오면 echo $$ > my.pid
실패 할 때 저장된 PID .lock
가 실제로 스크립트의 활성 인스턴스 인지 확인할 수 있습니다.
추가 도구가 필요없는 솔루션이 선호됩니다.
ln -s my.pid .lock
잠금 ()이 오면 echo $$ > my.pid
실패 할 때 저장된 PID .lock
가 실제로 스크립트의 활성 인스턴스 인지 확인할 수 있습니다.
답변:
nsg의 답변과 거의 비슷합니다 : lock directory 사용하십시오 . 디렉토리 생성은 리눅스와 유닉스, * BSD와 다른 많은 OS에서 원자 적입니다.
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
디버깅 목적으로 잠금 sh의 PID를 잠금 디렉토리의 파일에 넣을 수 있지만 잠금 프로세스가 여전히 실행 중인지 확인하기 위해 PID를 확인할 수 있다는 생각의 함정에 빠지지 마십시오. 많은 경쟁 조건이 그 길에 놓여 있습니다.
mkdir
NFS에서 원 자성이 아니라는 주장이 있습니다 (나에게 해당되지는 않지만 사실이라면 언급해야 할 것 같습니다)
/tmp
은 대개 NFS 공유가 아닌 lockdir 일 가능성이 높 으므로 괜찮을 것입니다.
rm -rf
잠금 디렉토리를 제거하는 데 사용 합니다. rmdir
누군가 (필요하지는 않지만) 디렉토리에 파일을 추가하면 실패합니다.
에 추가하려면 브루스 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
if ! mkdir "$LOCKDIR"; then handle failure to lock and exit; fi trap and do processing after if-statement
.
너무 간단 할 수 있습니다. 틀린 경우 수정 해주세요. 간단 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 $$
. 실제 예 : old-14532, new-1453, old-28858, new-858.
grep -v $$
grep -v "^${$} "
grep -wv "^$$"
(편집 참조).
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
도 나쁘지 않습니까?
$$
잠금 파일 에을 쓰면 경쟁 조건을 줄일 수 있습니다 . 그런 다음 sleep
짧은 간격으로 다시 읽으십시오. PID가 여전히 귀하의 것이라면, 잠금을 성공적으로 획득했습니다. 추가 도구가 필요하지 않습니다.
하나의 스크립트 인스턴스 만 실행되도록하려면 다음을 살펴보십시오.
그렇지 않으면 추가 도구를 호출하지 않기 때문에 check ps
또는 invoke 할 수 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
실제로는 이것으로 충분하거나 경쟁 조건에 취약합니까?
추가 도구가없는 솔루션을 요청했지만 다음을 사용하는 가장 좋아하는 방법입니다 flock
.
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
이는의 예제 섹션에서 제공되며 man flock
추가 설명은 다음과 같습니다.
이것은 쉘 스크립트에 유용한 상용구 코드입니다. 잠 그려는 쉘 스크립트의 맨 위에 놓으면 첫 번째 실행에서 자동으로 잠 깁니다. env var $ FLOCKER가 실행중인 쉘 스크립트로 설정되지 않은 경우, 올바른 인수로 다시 실행하기 전에 flock을 실행하고 독점적 인 비 차단 잠금 (스크립트 자체를 잠금 파일로 사용)을 가져옵니다. 또한 FLOCKER env var를 올바른 값으로 설정하여 다시 실행되지 않습니다.
고려해야 할 사항 :
flock
, 예제 스크립트를 찾을 수 없으면 오류와 함께 종료됩니다https://stackoverflow.com/questions/185451/quick-and-dirty-way-to-ensure-only-one-instance-of-a-shell-script-is-running-at 도 참조하십시오 .
이것은 Anselmo 's Answer의 수정 된 버전입니다 . 아이디어는 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"
다른 모든 답변과의 주요 차이점은이 코드는 파일 시스템을 수정하지 않고 매우 적은 공간을 사용하며 스크립트가 종료 상태와 독립적으로 완료되는 즉시 파일 설명자가 닫히므로 정리가 필요하지 않다는 것입니다. 따라서 스크립트가 실패하거나 성공하는지는 중요하지 않습니다.
exec 6< "$SCRIPT"
.
cksum을 사용하여 스크립트가 실제로 단일 인스턴스를 실행 하는지 확인하고 심지어 filename & file path를 변경합니다 .
트랩 및 잠금 파일을 사용하지 않습니다. 갑자기 서버가 다운되면 서버가 가동 된 후 수동으로 잠금 파일을 제거해야하기 때문입니다.
참고 : grep ps에는 첫 줄의 #! / bin / bash가 필요합니다.
#!/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
또는 스크립트 내에서 ckum을 하드 코딩 할 수 있으므로 스크립트의 파일 이름, 경로 또는 내용을 변경하려는 경우 다시 걱정할 필요가 없습니다 .
#!/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/sayanarijit/pidlock
sudo pip install -U pidlock
pidlock -n sleepy_script -c 'sleep 10'
당신에게 내 코드
#!/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
에을 넣을 때 모든 기본 스크립트를 넣을 수 있습니다.