때로는 하나의 쉘 스크립트 인스턴스 만 동시에 실행되고 있는지 확인해야합니다.
예를 들어 자체 잠금 기능을 제공하지 않는 크론을 통해 실행되는 크론 작업 (예 : 기본 Solaris 크론).
잠금을 구현하는 일반적인 패턴은 다음과 같은 코드입니다.
#!/bin/sh
LOCK=/var/tmp/mylock
if [ -f $LOCK ]; then # 'test' -> race begin
echo Job is already running\!
exit 6
fi
touch $LOCK # 'set' -> race end
# do some work
rm $LOCK
물론 이러한 코드에는 경쟁 조건이 있습니다. 두 번째 인스턴스의 실행이 $LOCK파일 을 터치하기 전에 3 행 이후에 진행될 수있는 시간 창이 있습니다.
크론 작업의 경우 두 호출 사이에 분 간격이 있으므로 일반적으로 문제가되지 않습니다.
그러나 잠금 파일이 NFS 서버에있을 때와 같이 상황이 잘못 될 수 있습니다. 이 경우 여러 cron 작업이 3 행에서 차단되어 대기 할 수 있습니다. NFS 서버가 다시 활성화 된 경우 병렬로 실행중인 작업 무리 가 있습니다.
웹에서 검색 하면 해당 문제에 대한 좋은 해결책 인 것처럼 보이는 도구 lockrun 을 발견했습니다 . 그것으로 당신은 다음과 같이 잠금이 필요한 스크립트를 실행합니다 :
$ lockrun --lockfile=/var/tmp/mylock myscript.sh
이것을 랩퍼에 넣거나 crontab에서 사용할 수 있습니다.
사용 lockf()가능한 경우 (POSIX)를 사용하고 flock()(BSD)로 폴백합니다. 그리고 lockf()NFS를 통한 지원은 비교적 광범위해야합니다.
대안이 lockrun있습니까?
다른 크론 데몬은 어떻습니까? 제정신 방식으로 잠금을 지원하는 공통 크론이 있습니까? Vixie Crond (데비안 / 우분투 시스템의 기본값) 매뉴얼 페이지를 잠깐 살펴보면 잠금에 관한 내용이 표시되지 않습니다.
이 같은 도구를 포함하는 것이 좋습니다 있을까 lockrun에 로 coreutils를 ?
내 의견으로는 timeout, nice및 친구와 매우 유사한 주제를 구현합니다 .
답변
쉘 스크립트에서 잠금을 수행하는 또 다른 방법은 위에서 설명한 경쟁 조건을 방지 할 수 있으며 두 작업이 모두 행 3을 통과 할 수 있습니다.이 noclobber옵션은 ksh 및 bash에서 작동합니다. set noclobbercsh / tcsh에서 스크립팅해서는 안되므로 사용하지 마십시오 . 😉
lockfile=/var/tmp/mylock
if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; then
trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -f "$lockfile"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockfile owned by $(cat $lockfile)"
fi
NFS에 잠금 기능이있는 YMMV (NFS 서버에 연결할 수없는 경우)는 일반적으로 예전보다 훨씬 강력합니다. (10 년 전)
여러 서버에서 동시에 동일한 작업을 수행하는 크론 작업이 있지만 실제로 실행하기 위해 인스턴스가 하나만 있으면이 작업이 효과적 일 수 있습니다.
lockrun에 대한 경험은 없지만 스크립트를 실제로 실행하기 전에 미리 설정된 잠금 환경이 있으면 도움이 될 수 있습니다. 아니면 그렇지 않을 수도 있습니다. 당신은 래퍼에서 스크립트 외부의 잠금 파일에 대한 테스트를 설정하고 있으며 이론적으로는 두 개의 작업이 정확히 동일한 시간에 lockrun에 의해 호출 된 경우 ‘inside- 스크립트 솔루션?
파일 잠금은 어쨌든 시스템 동작을 거의 존중하며, 실행 전에 잠금 파일의 존재를 확인하지 않는 스크립트는 무엇이든 할 것입니다. 잠금 파일 테스트와 적절한 동작을 수행하면 100 %가 아니라도 99 %의 잠재적 문제를 해결할 수 있습니다.
잠금 파일 경쟁 조건이 많이 발생하는 경우 작업 시간이 제대로 지정되지 않았거나 작업 완료만큼 간격이 중요하지 않은 경우보다 큰 문제를 나타내는 것일 수 있습니다. .
아래 편집-2016-05-06 (KSH88을 사용하는 경우)
아래 @Clint Pachl의 의견을 바탕으로 ksh88을 사용 mkdir하는 경우 대신을 사용하십시오 noclobber. 이것은 대부분 잠재적 인 경쟁 조건을 완화하지만 완전히 제한하지는 않습니다 (위험은 미미합니다). 자세한 내용 은 아래 Clint가 게시 한 링크를 참조하십시오 .
lockdir=/var/tmp/mylock
pidfile=/var/tmp/mylock/pid
if ( mkdir ${lockdir} ) 2> /dev/null; then
echo $$ > $pidfile
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT
# do stuff here
# clean up after yourself, and release your trap
rm -rf "$lockdir"
trap - INT TERM EXIT
else
echo "Lock Exists: $lockdir owned by $(cat $pidfile)"
fi
또한 스크립트에서 tmpfile을 작성해야하는 경우 스크립트 종료시 lockdir정리 될 것임을 알고 디렉토리를 사용할 수 있습니다 .
보다 현대적인 bash의 경우 상단의 noclobber 방법이 적합해야합니다.
답변
하드 링크를 선호합니다.
lockfile=/var/lock/mylock
tmpfile=${lockfile}.$$
echo $$ > $tmpfile
if ln $tmpfile $lockfile 2>&-; then
echo locked
else
echo locked by $(<$lockfile)
rm $tmpfile
exit
fi
trap "rm ${tmpfile} ${lockfile}" 0 1 2 3 15
# do what you need to
하드 링크는 NFS를 통한 원 자성 이며 대부분의 경우 mkdir도 마찬가지 입니다. 실제적인 수준에서 사용 mkdir(2)하거나 link(2)거의 동일; NFS보다 많은 구현이 atomic보다 atomic hard link를 허용했기 때문에 하드 링크를 선호합니다 mkdir. 최신 NFS 릴리스를 사용하면 둘 중 어느 것을 사용해도 걱정할 필요가 없습니다.
답변
나는 그것이 mkdir원자 적이라는 것을 이해합니다 .
lockdir=/var/tmp/myapp
if mkdir $lockdir; then
# this is a new instance, store the pid
echo $$ > $lockdir/PID
else
echo Job is already running, pid $(<$lockdir/PID) >&2
exit 6
fi
# then set traps to cleanup upon script termination
# ref http://www.shelldorado.com/goodcoding/tempfiles.html
trap 'rm -r "$lockdir" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15
답변
쉬운 방법은 패키지 lockfile와 함께 제공되는 것 procmail입니다.
LOCKFILE="/tmp/mylockfile.lock"
# try once to get the lock else exit
lockfile -r 0 "$LOCKFILE" || exit 0
# here the actual job
rm -f "$LOCKFILE"
답변
semGNU parallel도구의 일부로 제공되는 것은 당신이 찾고있는 것일 수 있습니다.
sem [--fg] [--id <id>] [--semaphoretimeout <secs>] [-j <num>] [--wait] command
에서처럼 :
sem --id my_semaphore --fg "echo 1 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 2 ; date ; sleep 3" &
sem --id my_semaphore --fg "echo 3 ; date ; sleep 3" &
출력 :
1
Thu 10 Nov 00:26:21 UTC 2016
2
Thu 10 Nov 00:26:24 UTC 2016
3
Thu 10 Nov 00:26:28 UTC 2016
주문이 보장되지는 않습니다. 또한 출력은 끝날 때까지 표시되지 않습니다 (자극!). 그러나 그럼에도 불구하고 잠금 파일과 재시도 및 정리에 대해 걱정하지 않고 동시 실행을 방지하는 가장 간결한 방법입니다.
답변
사용 dtach합니다.
$ dtach -n /tmp/socket long_running_task ; echo $?
0
$ dtach -n /tmp/socket long_running_task ; echo $?
dtach: /tmp/socket: Address already in use
1