한 번에 하나의 셸 스크립트 인스턴스 만 실행되도록하는 빠르고 더러운 방법


답변:


109

다음은 잠금 파일 을 사용 하고 PID를 에코 하는 구현입니다 . 이것은 pidfile을 제거하기 전에 프로세스가 종료 된 경우 보호 기능을합니다 .

LOCKFILE=/tmp/lock.txt
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
    echo "already running"
    exit
fi

# make sure the lockfile is removed when we exit and then claim it
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
echo $$ > ${LOCKFILE}

# do stuff
sleep 1000

rm -f ${LOCKFILE}

여기서 트릭은 kill -0신호를 전달하지 않지만 주어진 PID를 가진 프로세스가 존재하는지 확인하는 것입니다. 또한 호출하는 trap수 있도록합니다 잠금 파일은 프로세스가 (제외 사망하는 경우도 제거됩니다 kill -9).


73
다른 답변에 대한 주석에서 이미 언급했듯이 이것은 치명적인 결함이 있습니다. 다른 스크립트가 검사와 에코 사이에서 시작되면 토스트입니다.
Paul Tomblin

1
symlink 트릭은 깔끔하지만 lockfile의 소유자가 kill -9'd이거나 시스템이 충돌하는 경우 symlink를 읽어야하는 경쟁 조건이 여전히 존재하지만 소유자가 없어진 것을 확인한 후 삭제하십시오. 내 솔루션을 고수하고 있습니다.
bmdhacks

9
원자 검사 및 작성은 쉘 (1) 또는 잠금 파일 (1)을 사용하여 쉘에서 사용 가능합니다. 다른 답변을 참조하십시오.
dmckee --- 전 운영자 고양이

3
원자 검사를 수행하고 flock 또는 lockfile과 같은 유틸리티에 의존하지 않고 생성 할 수있는 이식 가능한 방법은 내 답변을 참조하십시오.
lhunath 2009

2
이것은 원자 적이 지 않으므로 쓸모가 없습니다. 테스트 및 설정을위한 원자 메커니즘이 필요합니다.
K Richard Pixley

214

사용은 flock(1)파일 기술자에 대한 독점적 인 범위의 잠금 A를 확인합니다. 이 방법으로 스크립트의 다른 부분을 동기화 할 수도 있습니다.

#!/bin/bash

(
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200 || exit 1

  # Do stuff

) 200>/var/lock/.myscript.exclusivelock

코드 사이의이 보장하지만 (하고 )한 번에 하나 개의 프로세스 만이 실행되는 프로세스가 너무 오래 잠금을 대기하지 않습니다.

주의 사항 :이 특정 명령은의 일부입니다 util-linux. Linux 이외의 운영 체제를 실행하는 경우 운영 체제가 사용 가능하지 않을 수 있습니다.


11
200은 무엇입니까? 그것은 manul에서 "fd"라고 말하지만 그게 무슨 뜻인지 모르겠습니다.
chovy

4
@chovy "파일 디스크립터", 열린 파일을 지정하는 정수 핸들.
Alex B

6
다른 사람이 궁금한 경우 : 구문 ( command A ) command B은에 대한 서브 쉘을 호출합니다 command A. tldp.org/LDP/abs/html/subshells.html에 문서화되어 있습니다 . 나는 서브 쉘 및 명령 B의 호출의 타이밍에 대해 확실하지 아직 생각
박사 1 월 필립 Gehrcke

1
하위 쉘 내부의 코드는 더 비슷해야한다고 if flock -x -w 10 200; then ...Do stuff...; else echo "Failed to lock file" 1>&2; fi생각합니다. 시간 초과가 발생하면 (일부 다른 프로세스에 파일이 잠겨있는 경우)이 스크립트는 진행되지 않고 파일을 수정하지 않습니다. 아마도 ... 반복 인수는 '10 초가 걸렸지 만 잠금을 여전히 사용할 수 없으면 절대 사용할 수 없게 될 것입니다. '아마도 잠금을 유지하는 프로세스가 종료되지 않기 때문일 수 있습니다. 디버거에서?).
Jonathan Leffler

1
리디렉션 된 파일은 잠금이 작동하는 장소 폴더 일 뿐이므로 의미있는 데이터가 없습니다. 는 exit안쪽 부분에서이다 ( ). 서브 프로세스가 종료되면 잠금을 보유하는 프로세스가 없으므로 잠금이 자동으로 해제됩니다.
clacke

158

"파일 잠금"의 존재를 테스트하는 모든 접근 방식에는 결함이 있습니다.

왜? 파일이 존재하는지 확인하고 단일 원자 조치로 파일을 작성할 수있는 방법이 없기 때문입니다. 이것 때문에; 경쟁 조건이 것입니다 상호 배제 휴식에 당신의 시도를이.

대신을 사용해야 mkdir합니다. mkdir디렉토리가 없으면 디렉토리를 작성하고 존재하면 종료 코드를 설정합니다. 더 중요한 것은 단일 원자 동작 으로이 모든 것을 수행 하여이 시나리오에 완벽하게 만듭니다.

if ! mkdir /tmp/myscript.lock 2>/dev/null; then
    echo "Myscript is already running." >&2
    exit 1
fi

자세한 내용은 우수한 BashFAQ를 참조하십시오. http://mywiki.wooledge.org/BashFAQ/045

오래된 잠금 장치를 관리하려면 퓨저 (1) 가 유용합니다. 여기서 유일한 단점은 작업이 약 1 초가 걸리므로 즉각적이지 않다는 것입니다.

다음은 퓨저를 사용하여 문제를 해결하는 함수입니다.

#       mutex file
#
# Open a mutual exclusion lock on the file, unless another process already owns one.
#
# If the file is already locked by another process, the operation fails.
# This function defines a lock on a file as having a file descriptor open to the file.
# This function uses FD 9 to open a lock on the file.  To release the lock, close FD 9:
# exec 9>&-
#
mutex() {
    local file=$1 pid pids 

    exec 9>>"$file"
    { pids=$(fuser -f "$file"); } 2>&- 9>&- 
    for pid in $pids; do
        [[ $pid = $$ ]] && continue

        exec 9>&- 
        return 1 # Locked by a pid.
    done 
}

다음과 같이 스크립트에서 사용할 수 있습니다.

mutex /var/run/myscript.lock || { echo "Already running." >&2; exit 1; }

이식성에 신경 쓰지 않는다면 (이 솔루션은 거의 모든 UNIX 상자에서 작동해야합니다) Linux의 fuser (1) 은 몇 가지 추가 옵션을 제공하며 flock (1)도 있습니다.


1
if ! mkdirlockdir 내부에 저장된 PID가있는 프로세스 (실패한 시작시)가 실제로 실행 중이고 스탈린 보호를위한 스크립트 동일한 지 여부를 확인 하는 데 파트를 결합 할 수 있습니다 . 또한 재부팅 후 PID를 재사용하지 못하도록 보호 할 수 있으며조차 필요하지 않습니다 fuser.
Tobias Kienzler

4
원 자성 조작으로 정의mkdir 되지 않았 으며 "부작용"이 파일 시스템의 구현 세부 사항 인 것은 확실합니다 . 그가 NFS가 원자적인 방식으로 그것을 구현하지 않는다고 말하면 그를 완전히 믿습니다. 비록 당신 이 NFS 공유가 될 것이라고 생각하지는 않지만 원자 적으로 구현하는 fs에 의해 제공 될 것 입니다. /tmpmkdir
lhunath

5
그러나 일반 파일이 있는지 확인하고 그렇지 않은 경우 원자 적으로 파일을 만드는 방법 ln이 있습니다. 다른 파일에서 하드 링크를 만드는 데 사용 합니다. 보장 할 수없는 이상한 파일 시스템이있는 경우 나중에 새 파일의 inode를 검사하여 파일이 원본 파일과 동일한 지 확인할 수 있습니다.
Juan Cespedes

4
이다 그것의 - '파일이 존재하는지 여부를 확인하고 하나의 원자 행동에 그것을 만들 수있는 방법이' open(... O_CREAT|O_EXCL). lockfile-create(in lockfile-progs) 또는 dotlockfile(in liblockfile-bin) 과 같이 적절한 사용자 프로그램이 필요합니다 . 또한 올바르게 청소 (예 trap EXIT:)하거나 오래된 잠금 장치 (예 :)를 테스트하십시오 --use-pid.
Toby Speight

5
"파일 잠금"의 존재를 테스트하는 모든 접근 방식에는 결함이 있습니다. 왜? 파일이 존재하는지 확인하고 단일 원자 동작으로 파일을 작성할 수있는 방법이 없기 때문에 "-원자화하려면 커널 수준-커널 수준에서 flock (1) linux.die.net/man/1/flock 으로 수행됩니다.이 권한 은 맨 저작권 날짜부터 2006 년 이후부터 있었던 것으로 보입니다. 1) 개인적인 것은 아니지만 커널 개발자가 제공하는 커널 구현 도구를 사용하는 것이 옳다는 확신이 있습니다.
크레이그 cks 스

42

flock (2) 시스템 호출에는 flock (1)이라고하는 래퍼가 있습니다. 이렇게하면 정리 등을 걱정하지 않고 독점 잠금을 비교적 쉽게 얻을 수 있습니다 . 셸 스크립트에서이를 사용하는 방법 에 대한 예제 가 맨 페이지 에 있습니다.


3
flock()시스템 호출은 POSIX하지 않고 NFS 마운트에서 파일을 작동하지 않습니다.
maxschlepzig

17
flock -x -n %lock file% -c "%command%"하나의 인스턴스 만 실행되도록하기 위해 사용하는 Cron 작업에서 실행
Ryall

Aww, 상상력이없는 flock (1) 대신 flock (U)와 같은 것을 사용해야했습니다. ... 그것에 익숙합니다. . 한두 시간 전에 들었던 것 같습니다.
Kent Kruckeberg

flock (2) 문서는 파일 만 사용하도록 지정하지만 flock (1) 문서는 파일 또는 디렉토리 사용을 지정합니다. flock (1) 문서는 작성 중 차이를 표시하는 방법에 대해 명시 적이 지 않지만 최종 "/"를 추가하여 수행한다고 가정합니다. 어쨌든 flock (1)이 디렉토리를 처리 할 수 ​​있지만 flock (2)는 처리 할 수없는 경우 flock (1)은 flock (2)에서만 구현되지 않습니다.
크레이그 cks 스

27

무리와 같은 원자 연산이 필요합니다. 그렇지 않으면 결국 실패합니다.

그러나 무리를 사용할 수 없으면 어떻게해야합니까? mkdir이 있습니다. 그것은 원자 작업입니다. 하나의 프로세스 만 mkdir을 성공적으로 수행하고 다른 프로세스는 모두 실패합니다.

코드는 다음과 같습니다.

if mkdir /var/lock/.myscript.exclusivelock
then
  # do stuff
  :
  rmdir /var/lock/.myscript.exclusivelock
fi

스크립트가 다시 실행되지 않는 충돌이 발생하면 오래된 잠금을 처리해야합니다.


1
"./a.sh & ./a.sh & ./a.sh & ./a.sh & ./a.sh & ./a.sh & ./a.sh와 같이 동시에 몇 번 실행하십시오. & ") 스크립트가 몇 번 새어 나옵니다.
Nippysaurus

7
@Nippysaurus :이 잠금 방법은 누출되지 않습니다. 당신이 본 것은 모든 복사본이 시작되기 전에 초기 스크립트가 종료되었으므로 다른 스크립트가 잠금을 올바르게 얻을 수있었습니다. 이 오탐을 피하려면 sleep 10이전을 추가하고 rmdir다시 캐스케이드를 시도하십시오. "누설"이 없습니다.
아토스 경

다른 소스는 mkdir이 NFS와 같은 일부 파일 시스템에서 원 자성이 아니라고 주장합니다. 그리고 btw는 NFS 동시 재귀 mkdir이 때로는 jenkins 매트릭스 작업에서 오류를 발생시키는 경우를 보았습니다. 그래서 나는 그것이 사실이라고 확신합니다. 그러나 mkdir은 덜 까다로운 사용 사례 IMO에 매우 좋습니다.
akostadinov

Bash의 noclobber 옵션을 일반 파일과 함께 사용할 수 있습니다.
Palec

26

잠금을 안정적으로 만들려면 원 자성 작업이 필요합니다. 위의 제안 중 많은 부분이 원자가 아닙니다. 제안 된 lockfile (1) 유틸리티는 언급 된 맨 페이지에서 "NFS- 내성"이라는 유망한 것으로 보입니다. OS가 lockfile (1)을 지원하지 않고 솔루션이 NFS에서 작동해야하는 경우 옵션이 많지 않습니다 ...

NFSv2에는 두 가지 원자 연산이 있습니다.

  • 심볼릭 링크
  • 이름을 바꾸다

NFSv3을 사용하면 create 호출도 원 자성입니다.

디렉토리 작업은 NFSv2 및 NFSv3에서 원자 적이 지 않습니다 (Brent Callaghan의 ISBN 'NFS Illustrated'(ISBN 0-201-32570-5, Brent는 Sun의 NFS 베테랑) 참조).

이것을 알면 파일과 디렉토리 (PHP가 아닌 셸)에 대한 스핀 잠금을 구현할 수 있습니다.

현재 디렉토리 잠금 :

while ! ln -s . lock; do :; done

파일을 잠그십시오.

while ! ln -s ${f} ${f}.lock; do :; done

현재 디렉토리 잠금 해제 (가정, 실행중인 프로세스가 실제로 잠금을 획득 함) :

mv lock deleteme && rm deleteme

파일 잠금 해제 (가정, 실행중인 프로세스가 실제로 잠금을 획득 함) :

mv ${f}.lock ${f}.deleteme && rm ${f}.deleteme

제거도 원자가 아니므로 먼저 원자 이름을 변경 한 다음 제거하십시오.

심볼릭 링크 및 이름 바꾸기 호출의 경우 두 파일 이름이 모두 동일한 파일 시스템에 있어야합니다. 내 제안 : 간단한 파일 이름 (경로 없음) 만 사용하고 파일을 넣고 동일한 디렉토리에 고정하십시오.


mkdir이 NFS보다 원자 적이 지 않다는 문장을 지원하는 NFS Illustrated 페이지는 무엇입니까?
maxschlepzig

이 기술에 대한 생각. 쉘 뮤텍스 구현은 나의 새로운 쉘 lib : github.com/Offirmo/offirmo-shell-lib 에서 가능하다. "mutex"를 보라. 이 사용 lockfile가능한 경우, 또는 대체이로 symlink하지 않을 경우 방법.
Offirmo

좋은. 불행히도이 방법은 오래된 잠금을 자동으로 삭제하는 방법을 제공하지 않습니다.
Richard Hansen

두 단계 P1, P2가 경주하는 경우가 아니라 두 단계 잠금 해제 ( mv, rm)를 사용해야 합니까? 예를 들어, P1은로 잠금 해제를 시작한 다음 P2 잠금, P2 잠금 해제 ( 및 모두 )를 시작하고 마지막으로 P1이 시도 하고 실패합니다. rm -frmmvmvrmrm
매트 월리스

1
@MattWallis 마지막 문제 $$${f}.deleteme파일 이름 에 포함시켜 쉽게 완화 할 수 있습니다 .
Stefan Majewsky

23

또 다른 옵션은을 noclobber실행 하여 쉘 옵션을 사용 하는 것 set -C입니다. 그때> 파일이 이미 존재하는 경우 실패합니다.

간단히 :

set -C
lockfile="/tmp/locktest.lock"
if echo "$$" > "$lockfile"; then
    echo "Successfully acquired lock"
    # do work
    rm "$lockfile"    # XXX or via trap - see below
else
    echo "Cannot acquire lock - already locked by $(cat "$lockfile")"
fi

쉘이 다음을 호출하게합니다.

open(pathname, O_CREAT|O_EXCL)

원자 적으로 파일을 작성하거나 파일이 이미 존재하는 경우 실패합니다.


BashFAQ 045 에 대한 의견에 따르면 이것은 실패 할 수 ksh88있지만 모든 쉘에서 작동합니다.

$ strace -e trace=creat,open -f /bin/bash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/zsh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/pdksh /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_LARGEFILE, 0666) = 3

$ strace -e trace=creat,open -f /bin/dash /home/mikel/bin/testopen 2>&1 | grep -F testopen.lock
open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3

플래그 를 pdksh추가하는 O_TRUNC것이 흥미롭지 만 분명히 중복됩니다.
빈 파일을 만들거나 아무것도하지 않습니다.


rm부정 행위 를 처리 할 방법에 따라 방법이 달라집니다.

정리 종료시 삭제

부정확 한 종료가 발생한 문제가 해결되고 잠금 파일이 수동으로 제거 될 때까지 새 실행이 실패합니다.

# acquire lock
# do work (code here may call exit, etc.)
rm "$lockfile"

모든 출구에서 삭제

스크립트가 아직 실행되고 있지 않으면 새로운 실행이 성공합니다.

trap 'rm "$lockfile"' EXIT

매우 참신한 접근 방법 ... 이것은 잠금 디렉토리가 아닌 잠금 파일을 사용하여 원 자성을 달성하는 한 가지 방법으로 보입니다.
매트 콜드웰

좋은 접근법. :-) EXIT 트랩에서는 잠금 파일을 정리할 수있는 프로세스를 제한해야합니다. 예를 들면 다음과 같습니다. trap 'if [[$ (cat "$ lockfile") == "$$"]]; 그런 다음 rm "$ lockfile"; fi 'EXIT
Kevin Seifert

1
잠금 파일은 NFS를 통해 원자 적이 지 않습니다. 이것이 사람들이 잠금 디렉토리를 사용하는 이유입니다.
K Richard Pixley

20

GNU Parallel로 호출 할 때 뮤텍스로 작동하므로 이것을 사용할 수 있습니다 sem. 따라서 구체적인 용어로 다음을 사용할 수 있습니다.

sem --id SCRIPTSINGLETON yourScript

시간 초과를 원하면 다음을 사용하십시오.

sem --id SCRIPTSINGLETON --semaphoretimeout -10 yourScript

시간 종료 <0은 시간 종료 내에 세마포어가 해제되지 않은 경우 스크립트를 실행하지 않고 종료하는 것을 의미하며, 시간 종료> 0은 스크립트를 실행하는 것을 의미합니다.

이름을 (로 --id) 지정해야하며 그렇지 않으면 제어 터미널이 기본값이됩니다.

GNU Parallel 대부분의 Linux / OSX / Unix 플랫폼에서 설치가 매우 간단합니다. Perl 스크립트 일뿐입니다.


너무 나쁜 사람들은 쓸모없는 답변을 거절하는 것을 꺼려합니다. 이는 새로운 더미에 정크에 묻 힙니다.
Dmitry Grigoryev

4
우리는 단지 많은 투표를 필요로합니다. 이것은 깔끔하고 거의 알려지지 않은 대답입니다. (절대적으로 OP가 되기는했지만 빠르고 더러움을 원했지만 이것은 빠르고 깨끗합니다!) sem관련 질문 unix.stackexchange.com/a/322200/199525 에서 자세히 알아보십시오 .
부분적으로 흐린

16

쉘 스크립트의 경우, 나는 mkdir오버 와 함께 경향이flock 경우 잠금을 더 이식 가능하게 만들면서 났습니다.

어느 쪽이든 set -e 것만으로는 충분하지 않습니다. 명령이 실패하면 스크립트를 종료합니다. 자물쇠는 여전히 남아 있습니다.

적절한 잠금 정리를 위해서는 트랩을이 의사 코드와 같이 설정해야합니다 (리프팅, 단순화 및 테스트되지 않았지만 활발하게 사용되는 스크립트에서).

#=======================================================================
# Predefined Global Variables
#=======================================================================

TMPDIR=/tmp/myapp
[[ ! -d $TMP_DIR ]] \
    && mkdir -p $TMP_DIR \
    && chmod 700 $TMPDIR

LOCK_DIR=$TMP_DIR/lock

#=======================================================================
# Functions
#=======================================================================

function mklock {
    __lockdir="$LOCK_DIR/$(date +%s.%N).$$" # Private Global. Use Epoch.Nano.PID

    # If it can create $LOCK_DIR then no other instance is running
    if $(mkdir $LOCK_DIR)
    then
        mkdir $__lockdir  # create this instance's specific lock in queue
        LOCK_EXISTS=true  # Global
    else
        echo "FATAL: Lock already exists. Another copy is running or manually lock clean up required."
        exit 1001  # Or work out some sleep_while_execution_lock elsewhere
    fi
}

function rmlock {
    [[ ! -d $__lockdir ]] \
        && echo "WARNING: Lock is missing. $__lockdir does not exist" \
        || rmdir $__lockdir
}

#-----------------------------------------------------------------------
# Private Signal Traps Functions {{{2
#
# DANGER: SIGKILL cannot be trapped. So, try not to `kill -9 PID` or 
#         there will be *NO CLEAN UP*. You'll have to manually remove 
#         any locks in place.
#-----------------------------------------------------------------------
function __sig_exit {

    # Place your clean up logic here 

    # Remove the LOCK
    [[ -n $LOCK_EXISTS ]] && rmlock
}

function __sig_int {
    echo "WARNING: SIGINT caught"    
    exit 1002
}

function __sig_quit {
    echo "SIGQUIT caught"
    exit 1003
}

function __sig_term {
    echo "WARNING: SIGTERM caught"    
    exit 1015
}

#=======================================================================
# Main
#=======================================================================

# Set TRAPs
trap __sig_exit EXIT    # SIGEXIT
trap __sig_int INT      # SIGINT
trap __sig_quit QUIT    # SIGQUIT
trap __sig_term TERM    # SIGTERM

mklock

# CODE

exit # No need for cleanup code here being in the __sig_exit trap function

어떻게 될까요? 모든 트랩은 출구를 생성하므로 __sig_exit잠금을 정리 하는 기능 이 항상 발생합니다 (SIGKILL 제외).

참고 : 이탈 값은 낮은 값이 아닙니다. 왜? 다양한 배치 처리 시스템은 0에서 31까지의 숫자를 기대하거나 갖습니다.이를 다른 것으로 설정하면 스크립트 및 배치 스트림이 이전 배치 작업 또는 스크립트에 따라 반응하도록 할 수 있습니다.


2
스크립트가 너무 장황하여 생각보다 훨씬 짧을 수도 있지만 전반적으로 그렇습니다. 트랩을 올바르게 설정해야합니다. 또한 SIGHUP을 추가하겠습니다.
mojuba

$ LOCK_DIR을 확인하는 반면 $ __ lockdir을 제거하는 것을 제외하고는 잘 작동합니다. 어쩌면 잠금을 제거 할 때 rm -r $ LOCK_DIR을 수행 할 것을 제안해야합니까?
bevada

제안 해 주셔서 감사합니다. 위의 코드는 해제되고 의사 코드 방식으로 배치되었으므로 사람들의 사용에 따라 조정해야합니다. 그러나 rmdir은 디렉토리 가 비어있는 경우 only_ 디렉토리를 안전하게 제거하므로 내 경우에는 의도적으로 rmdir을 사용했습니다 . 사람들이 PID 파일 등과 같은 리소스를 리소스에 배치하는 경우 잠금 정리를보다 적극적으로 변경 rm -r $LOCK_DIR하거나 필요에 따라 강제로 수정해야합니다 (상대 스크래치 파일을 보유하는 것과 같은 특수한 경우에도 마찬가지입니다). 건배.
Mark Stinson

테스트 했습니까 exit 1002?
Gilles Quenot 2016 년

13

정말 빠르고 정말 더럽습니까? 스크립트 상단에있는이 하나의 라이너는 다음과 같이 작동합니다.

[[ $(pgrep -c "`basename \"$0\"`") -gt 1 ]] && exit

물론 스크립트 이름이 고유한지 확인하십시오. :)


테스트하기 위해 이것을 어떻게 시뮬레이션합니까? 스크립트를 한 줄에 두 번 시작하고 이미 실행 중일 경우 경고를받을 수있는 방법이 있습니까?
rubo77

2
이것은 전혀 작동하지 않습니다! 왜 확인 -gt 2합니까? grep이 ps의 결과에서 항상 자신을 찾지는 않습니다!
rubo77

pgrepPOSIX에 없습니다. 이 작업을 이식 가능하게하려면 POSIX가 필요 ps하고 출력을 처리하십시오.
Palec

OSX -c가 존재하지 않으면를 사용해야 | wc -l합니다. 숫자 비교 정보 : -gt 1첫 번째 인스턴스 자체를 확인한 후 확인됩니다.
Benjamin Peter

6

원자 디렉토리 잠금과 PID를 통한 오래된 잠금 확인을 결합하고 오래된 경우 다시 시작하는 방법이 있습니다. 또한 이것은 bashism에 의존하지 않습니다.

#!/bin/dash

SCRIPTNAME=$(basename $0)
LOCKDIR="/var/lock/${SCRIPTNAME}"
PIDFILE="${LOCKDIR}/pid"

if ! mkdir $LOCKDIR 2>/dev/null
then
    # lock failed, but check for stale one by checking if the PID is really existing
    PID=$(cat $PIDFILE)
    if ! kill -0 $PID 2>/dev/null
    then
       echo "Removing stale lock of nonexistent PID ${PID}" >&2
       rm -rf $LOCKDIR
       echo "Restarting myself (${SCRIPTNAME})" >&2
       exec "$0" "$@"
    fi
    echo "$SCRIPTNAME is already running, bailing out" >&2
    exit 1
else
    # lock successfully acquired, save PID
    echo $$ > $PIDFILE
fi

trap "rm -rf ${LOCKDIR}" QUIT INT TERM EXIT


echo hello

sleep 30s

echo bye

5

알려진 위치에 잠금 파일을 작성하고 스크립트 시작시 존재 여부를 확인 하시겠습니까? 누군가 PID를 파일에 넣으면 스크립트 실행을 방해하는 잘못된 인스턴스를 추적하려는 경우 도움이 될 수 있습니다.


5

이 예제는 man flock에 설명되어 있지만 버그와 종료 코드를 관리해야하기 때문에 약간의 노력이 필요합니다.

   #!/bin/bash
   #set -e this is useful only for very stupid scripts because script fails when anything command exits with status more than 0 !! without possibility for capture exit codes. not all commands exits >0 are failed.

( #start subprocess
  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
  flock -x -w 10 200
  if [ "$?" != "0" ]; then echo Cannot lock!; exit 1; fi
  echo $$>>/var/lock/.myscript.exclusivelock #for backward lockdir compatibility, notice this command is executed AFTER command bottom  ) 200>/var/lock/.myscript.exclusivelock.
  # Do stuff
  # you can properly manage exit codes with multiple command and process algorithm.
  # I suggest throw this all to external procedure than can properly handle exit X commands

) 200>/var/lock/.myscript.exclusivelock   #exit subprocess

FLOCKEXIT=$?  #save exitcode status
    #do some finish commands

exit $FLOCKEXIT   #return properly exitcode, may be usefull inside external scripts

다른 방법을 사용하고 과거에 사용한 프로세스를 나열 할 수 있습니다. 그러나 이것은 위의 방법보다 더 복잡합니다. 기생충 nad 제거를 위해 ps, 프로세스 이름, 추가 필터 grep -v grep로 프로세스를 나열해야합니다. 숫자와 비교하십시오. 복잡하고 불확실하다


1
ln -s를 사용할 수 있습니다. mkdir과 ​​같은 파일 또는 symlink가없는 경우에만 symlink를 작성할 수 있습니다. 과거에는 많은 시스템 프로세스가 예를 들어 init 또는 inetd와 같은 심볼릭 링크를 사용했습니다. synlink는 프로세스 ID를 유지하지만 실제로 아무것도 가리 키지 않습니다. 몇 년 동안이 행동이 변경되었습니다. 프로세스는 플록과 세마포어를 사용합니다.
Znik

5

게시 된 기존 답변은 CLI 유틸리티를 사용 flock하거나 잠금 파일을 제대로 보호하지 않습니다. flock 유틸리티는 모든 비 Linux 시스템 (예 : FreeBSD)에서 사용할 수 없으며 NFS에서 제대로 작동하지 않습니다.

시스템 관리 및 시스템 개발의 제 초기에, 나는 잠금 파일을 만드는 안전하고 상대적으로 휴대용 방법을 사용하여 임시 파일을 생성하는 것을 들었다 mkemp(3)거나 mkemp(1), 임시 파일 (예 : PID)에 식별 정보를 기입 한 후 하드 링크 잠금 파일에 임시 파일. 연결에 성공하면 잠금을 획득 한 것입니다.

쉘 스크립트에서 잠금을 사용하는 경우 일반적으로 obtain_lock()공유 프로파일에 함수를 배치 한 다음 스크립트에서 소스를 제공합니다. 아래는 내 잠금 기능의 예입니다.

obtain_lock()
{
  LOCK="${1}"
  LOCKDIR="$(dirname "${LOCK}")"
  LOCKFILE="$(basename "${LOCK}")"

  # create temp lock file
  TMPLOCK=$(mktemp -p "${LOCKDIR}" "${LOCKFILE}XXXXXX" 2> /dev/null)
  if test "x${TMPLOCK}" == "x";then
     echo "unable to create temporary file with mktemp" 1>&2
     return 1
  fi
  echo "$$" > "${TMPLOCK}"

  # attempt to obtain lock file
  ln "${TMPLOCK}" "${LOCK}" 2> /dev/null
  if test $? -ne 0;then
     rm -f "${TMPLOCK}"
     echo "unable to obtain lockfile" 1>&2
     if test -f "${LOCK}";then
        echo "current lock information held by: $(cat "${LOCK}")" 1>&2
     fi
     return 2
  fi
  rm -f "${TMPLOCK}"

  return 0;
};

다음은 잠금 기능을 사용하는 방법의 예입니다.

#!/bin/sh

. /path/to/locking/profile.sh
PROG_LOCKFILE="/tmp/myprog.lock"

clean_up()
{
  rm -f "${PROG_LOCKFILE}"
}

obtain_lock "${PROG_LOCKFILE}"
if test $? -ne 0;then
   exit 1
fi
trap clean_up SIGHUP SIGINT SIGTERM

# bulk of script

clean_up
exit 0
# end of script

전화해야합니다 clean_up스크립트의 종료점 .

나는 리눅스와 FreeBSD 환경에서 위의 것을 사용했다.


4

데비안 머신을 대상으로 할 때 lockfile-progs패키지가 좋은 해결책이라고 생각합니다. 도구 procmail도 함께 제공됩니다 lockfile. 그러나 때때로 나는 이것들 중 어느 것에도 붙어 있지 않습니다.

다음 mkdir은 원 자성 및 PID 파일을 사용하여 오래된 잠금을 감지하는 솔루션입니다 . 이 코드는 현재 Cygwin 설정에서 제작 중이며 제대로 작동합니다.

그것을 사용하려면 exclusive_lock_require무언가에 독점적으로 액세스해야 할 때 전화하십시오 . 선택적 잠금 이름 매개 변수를 사용하면 다른 스크립트간에 잠금을 공유 할 수 있습니다. 더 복잡한 것이 필요한 경우 에는 두 가지 하위 수준 함수 ( exclusive_lock_tryexclusive_lock_retry)가 있습니다.

function exclusive_lock_try() # [lockname]
{

    local LOCK_NAME="${1:-`basename $0`}"

    LOCK_DIR="/tmp/.${LOCK_NAME}.lock"
    local LOCK_PID_FILE="${LOCK_DIR}/${LOCK_NAME}.pid"

    if [ -e "$LOCK_DIR" ]
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        if [ ! -z "$LOCK_PID" ] && kill -0 "$LOCK_PID" 2> /dev/null
        then
            # locked by non-dead process
            echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
            return 1
        else
            # orphaned lock, take it over
            ( echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null && local LOCK_PID="$$"
        fi
    fi
    if [ "`trap -p EXIT`" != "" ]
    then
        # already have an EXIT trap
        echo "Cannot get lock, already have an EXIT trap"
        return 1
    fi
    if [ "$LOCK_PID" != "$$" ] &&
        ! ( umask 077 && mkdir "$LOCK_DIR" && umask 177 && echo $$ > "$LOCK_PID_FILE" ) 2> /dev/null
    then
        local LOCK_PID="`cat "$LOCK_PID_FILE" 2> /dev/null`"
        # unable to acquire lock, new process got in first
        echo "\"$LOCK_NAME\" lock currently held by PID $LOCK_PID"
        return 1
    fi
    trap "/bin/rm -rf \"$LOCK_DIR\"; exit;" EXIT

    return 0 # got lock

}

function exclusive_lock_retry() # [lockname] [retries] [delay]
{

    local LOCK_NAME="$1"
    local MAX_TRIES="${2:-5}"
    local DELAY="${3:-2}"

    local TRIES=0
    local LOCK_RETVAL

    while [ "$TRIES" -lt "$MAX_TRIES" ]
    do

        if [ "$TRIES" -gt 0 ]
        then
            sleep "$DELAY"
        fi
        local TRIES=$(( $TRIES + 1 ))

        if [ "$TRIES" -lt "$MAX_TRIES" ]
        then
            exclusive_lock_try "$LOCK_NAME" > /dev/null
        else
            exclusive_lock_try "$LOCK_NAME"
        fi
        LOCK_RETVAL="${PIPESTATUS[0]}"

        if [ "$LOCK_RETVAL" -eq 0 ]
        then
            return 0
        fi

    done

    return "$LOCK_RETVAL"

}

function exclusive_lock_require() # [lockname] [retries] [delay]
{
    if ! exclusive_lock_retry "$@"
    then
        exit 1
    fi
}

고마워, cygwin에서 직접 시도해 보았고 간단한 테스트를 통과했습니다.
ndemou 2016 년

4

이 스레드의 다른 곳에서 이미 설명한 무리의 제한이 문제가되지 않으면 다음과 같이 작동합니다.

#!/bin/bash

{
    # exit if we are unable to obtain a lock; this would happen if 
    # the script is already running elsewhere
    # note: -x (exclusive) is the default
    flock -n 100 || exit

    # put commands to run here
    sleep 100
} 100>/tmp/myjob.lock 

3
-x (쓰기 잠금)가 이미 기본적으로 설정되어 있다고 지적했습니다.
Keldon Alleyne

그리고 -n것입니다 exit 1그것은 잠금을 얻을 수없는 경우 즉시
Anentropic

@KeldonAlleyne에게 감사합니다. 기본값 인 "-x"를 제거하도록 코드를 업데이트했습니다.
presto8

3

일부 유닉스는 lockfile 이미 언급 한 것과 매우 유사합니다 flock.

맨 페이지에서 :

lockfile은 하나 이상의 세마포어 파일을 작성하는 데 사용될 수 있습니다. lock-file이 지정된 모든 파일을 지정된 순서대로 작성할 수 없으면 휴면 시간 (기본값 8 초) 동안 대기 한 후 성공하지 못한 마지막 파일을 재 시도합니다. 실패가 리턴 될 때까지 재시도 횟수를 지정할 수 있습니다. 재시도 횟수가 -1 (기본값, -r-1)이면 잠금 파일이 영구적으로 재 시도됩니다.


우리는 어떻게 lockfile유틸리티를 얻 습니까?
Offirmo

lockfile와 함께 배포됩니다 procmail. 또한 패키지 dotlockfile와 함께 제공 되는 대안 이 liblockfile있습니다. 둘 다 NFS에서 안정적으로 작동한다고 주장합니다.
Mr. Deathless

3

실제로 bmdhacks의 대답은 거의 좋지만 잠금 파일을 처음 확인한 후 기록하기 전에 두 번째 스크립트가 실행될 가능성이 약간 있습니다. 따라서 둘 다 잠금 파일을 작성하고 둘 다 실행됩니다. 확실하게 작동시키는 방법은 다음과 같습니다.

lockfile=/var/lock/myscript.lock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null ; then
  trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
else
  # or you can decide to skip the "else" part if you want
  echo "Another instance is already running!"
fi

noclobber옵션은 파일이 이미 존재하는 경우 경로 재 지정 명령이 실패하는지 확인합니다. 따라서 redirect 명령은 실제로 원자 적입니다. 하나의 명령으로 파일을 작성하고 확인하십시오. 파일 끝에서 잠금 파일을 제거 할 필요는 없습니다. 트랩에 의해 제거됩니다. 나는 이것이 나중에 읽을 사람들에게 도움이되기를 바랍니다.

추신 : 나는 Mikel이 이미 질문에 올바르게 대답 한 것을 보지 못했지만, 예를 들어 Ctrl-C로 스크립트를 중지 한 후 잠금 파일이 남을 가능성을 줄이기 위해 trap 명령을 포함하지 않았습니다. 이것이 완벽한 솔루션입니다


3

잠금 파일, lockdir, 특수 잠금 프로그램을 제거하고 pidof모든 Linux 설치에서 찾을 수 없기 때문에 제거하고 싶었습니다 . 또한 가능한 가장 간단한 코드 (또는 가능한 한 적은 수의 행)를 원했습니다. if한 줄로 가장 간단한 진술 :

if [[ $(ps axf | awk -v pid=$$ '$1!=pid && $6~/'$(basename $0)'/{print $1}') ]]; then echo "Already running"; exit; fi

1
이것은 내 컴퓨터의 'ps'출력에 민감합니다 (우분투 14.04, procps-ng 버전 3.3.9의 / bin / ps) 'ps axf'명령은 필드 번호를 방해하는 ASCII 트리 문자를 인쇄합니다. 이것은 나를 위해 일했다 : /bin/ps -a --format pid,cmd | awk -v pid=$$ '/'$(basename $0)'/ { if ($1!=pid) print $1; }'
qneill

2

오래된 잠금 파일을 처리하는 간단한 방법을 사용합니다.

pid를 저장하는 위의 솔루션 중 일부는 pid가 랩핑 될 수 있다는 사실을 무시하십시오. 따라서 저장된 pid로 유효한 프로세스가 있는지 확인하는 것만으로는 충분하지 않습니다. 특히 장시간 실행되는 스크립트의 경우 충분합니다.

noclobber를 사용하여 한 번에 하나의 스크립트 만 열고 잠금 파일에 쓸 수 있도록합니다. 또한 잠금 파일에서 프로세스를 고유하게 식별하기에 충분한 정보를 저장합니다. 나는 pid, ppid, lstart 할 프로세스를 고유하게 식별하기 위해 데이터 세트를 정의합니다.

새 스크립트가 시작될 때 잠금 파일을 작성하지 못하면 잠금 파일을 작성한 프로세스가 여전히 주위에 있는지 확인합니다. 그렇지 않다면, 우리는 원래의 프로세스가 부적절하게 사망하여 오래된 잠금 파일을 남겼다고 가정합니다. 그런 다음 새 스크립트는 잠금 파일의 소유권을 가져 오며 모두 다시 세상에 있습니다.

여러 플랫폼에서 여러 쉘로 작업해야합니다. 빠르고 휴대가 간편합니다.

#!/usr/bin/env sh
# Author: rouble

LOCKFILE=/var/tmp/lockfile #customize this line

trap release INT TERM EXIT

# Creates a lockfile. Sets global variable $ACQUIRED to true on success.
# 
# Returns 0 if it is successfully able to create lockfile.
acquire () {
    set -C #Shell noclobber option. If file exists, > will fail.
    UUID=`ps -eo pid,ppid,lstart $$ | tail -1`
    if (echo "$UUID" > "$LOCKFILE") 2>/dev/null; then
        ACQUIRED="TRUE"
        return 0
    else
        if [ -e $LOCKFILE ]; then 
            # We may be dealing with a stale lock file.
            # Bring out the magnifying glass. 
            CURRENT_UUID_FROM_LOCKFILE=`cat $LOCKFILE`
            CURRENT_PID_FROM_LOCKFILE=`cat $LOCKFILE | cut -f 1 -d " "`
            CURRENT_UUID_FROM_PS=`ps -eo pid,ppid,lstart $CURRENT_PID_FROM_LOCKFILE | tail -1`
            if [ "$CURRENT_UUID_FROM_LOCKFILE" == "$CURRENT_UUID_FROM_PS" ]; then 
                echo "Script already running with following identification: $CURRENT_UUID_FROM_LOCKFILE" >&2
                return 1
            else
                # The process that created this lock file died an ungraceful death. 
                # Take ownership of the lock file.
                echo "The process $CURRENT_UUID_FROM_LOCKFILE is no longer around. Taking ownership of $LOCKFILE"
                release "FORCE"
                if (echo "$UUID" > "$LOCKFILE") 2>/dev/null; then
                    ACQUIRED="TRUE"
                    return 0
                else
                    echo "Cannot write to $LOCKFILE. Error." >&2
                    return 1
                fi
            fi
        else
            echo "Do you have write permissons to $LOCKFILE ?" >&2
            return 1
        fi
    fi
}

# Removes the lock file only if this script created it ($ACQUIRED is set), 
# OR, if we are removing a stale lock file (first parameter is "FORCE") 
release () {
    #Destroy lock file. Take no prisoners.
    if [ "$ACQUIRED" ] || [ "$1" == "FORCE" ]; then
        rm -f $LOCKFILE
    fi
}

# Test code
# int main( int argc, const char* argv[] )
echo "Acquring lock."
acquire
if [ $? -eq 0 ]; then 
    echo "Acquired lock."
    read -p "Press [Enter] key to release lock..."
    release
    echo "Released lock."
else
    echo "Unable to acquire lock."
fi

다른 해결책으로 +1을주었습니다. 대체로 AIX에서 작동하지 않습니다 (> ps -eo pid, ppid, lstart $$ | tail -1 ps : -o가있는 잘못된 목록). HP-UX가 아닙니다 (> ps -eo pid, ppid, lstart $$ tail -1 ps : 잘못된 옵션-o). 감사.
Tagar

2

스크립트 시작 부분에이 줄을 추가하십시오

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

맨 무리의 상용구 코드입니다.

더 많은 로깅을 원하면이 것을 사용하십시오

[ "${FLOCKER}" != "$0" ] && { echo "Trying to start build from queue... "; exec bash -c "FLOCKER='$0' flock -E $E_LOCKED -en '$0' '$0' '$@' || if [ \"\$?\" -eq $E_LOCKED ]; then echo 'Locked.'; fi"; } || echo "Lock is free. Completing."

flock유틸리티를 사용하여 잠금을 설정하고 확인 합니다. 이 코드는 스크립트 이름으로 설정되지 않은 경우 FLOCKER 변수를 확인하여 처음으로 실행되었는지 감지 한 다음 Flocker 변수를 초기화하고 FLOCKER 변수가 초기화 된 상태에서 스크립트를 다시 재귀 적으로 시작하려고 시도합니다. 성공했고 계속해도 괜찮습니다. 잠금이 사용 중이면 구성 가능한 종료 코드로 실패합니다.

데비안 7에서는 작동하지 않는 것 같지만 실험적인 util-linux 2.25 패키지에서는 다시 작동하는 것 같습니다. "flock : ... Text file busy"라고 씁니다. 스크립트에 대한 쓰기 권한을 비활성화하여 재정의 할 수 있습니다.


1

PID 및 잠금 파일이 가장 안정적입니다. 프로그램을 실행하려고 할 때 잠금 파일이 있는지 확인하고, 존재하는 ps경우 프로세스가 여전히 실행 중인지 확인하는 데 사용할 수 있습니다 . 그렇지 않은 경우 스크립트가 시작되어 잠금 파일의 PID를 자체로 업데이트 할 수 있습니다.


1

bmdhack의 솔루션이 적어도 내 유스 케이스에서 가장 실용적인 것으로 나타났습니다. flock 및 lockfile을 사용하면 스크립트가 종료 될 때 rm을 사용하여 lockfile을 제거해야하므로 항상 보장 할 수는 없습니다 (예 : kill -9).

bmdhack의 솔루션에 대한 사소한 점 하나를 변경하려고합니다.이 세마포어의 안전한 작동에 필요하지 않다는 것을 말하지 않고 잠금 파일을 제거합니다. kill -0을 사용하면 사용 불능 프로세스에 대한 이전 잠금 파일이 무시되거나 덮어 쓰기됩니다.

따라서 단순화 된 솔루션은 다음을 싱글 톤 맨 위에 간단히 추가하는 것입니다.

## Test the lock
LOCKFILE=/tmp/singleton.lock 
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
    echo "Script already running. bye!"
    exit 
fi

## Set the lock 
echo $$ > ${LOCKFILE}

물론이 스크립트에는 잠금 테스트 및 설정 작업이 단일 원자 작업이 아니기 때문에 동시에 시작될 가능성이있는 프로세스에 경쟁 위험이 있다는 결점이 있습니다. 그러나 lhunath가 mkdir을 사용하도록 제안한 해결책은 종료 된 스크립트가 디렉토리 뒤에 남겨져 다른 인스턴스가 실행되지 못하게하는 결함이 있습니다.


1

semaphoric 실용 용도 flock(AS presto8 의해 예 상술)을 구현하는 카운팅 세마포어 . 원하는 특정 수의 동시 프로세스를 사용할 수 있습니다. 다양한 큐 워커 프로세스의 동시성 레벨을 제한하기 위해이를 사용합니다.

그것은 sem과 같지만 훨씬 가볍습니다. (전체 공개 : 나는 sem이 우리의 요구에 너무 무거워서 사용할 수있는 간단한 세마포어 유틸리티가 없다는 것을 알게 된 후에 썼다.)


1

flock (1)이지만 서브 쉘이없는 예. flock () 파일 / tmp / foo는 절대 제거되지 않지만 flock () 및 un-flock ()을 가져 오기 때문에 중요하지 않습니다.

#!/bin/bash

exec 9<> /tmp/foo
flock -n 9
RET=$?
if [[ $RET -ne 0 ]] ; then
    echo "lock failed, exiting"
    exit
fi

#Now we are inside the "critical section"
echo "inside lock"
sleep 5
exec 9>&- #close fd 9, and release lock

#The part below is outside the critical section (the lock)
echo "lock released"
sleep 5

1

외부 의존성이 필요없는 이미 백만 번이나 다른 방법으로 답변했습니다.

LOCK_FILE="/var/lock/$(basename "$0").pid"
trap "rm -f ${LOCK_FILE}; exit" INT TERM EXIT
if [[ -f $LOCK_FILE && -d /proc/`cat $LOCK_FILE` ]]; then
   // Process already exists
   exit 1
fi
echo $$ > $LOCK_FILE

현재 PID ($$)를 잠금 파일에 쓸 때마다 스크립트 시작시 프로세스가 최신 PID로 실행 중인지 확인합니다.


1
트랩 호출이 없으면 (또는 일반적인 경우에는 거의 마지막에 정리), 마지막 실행 후에 잠금 파일이 남아 있고 나중에 다른 프로세스에서 PID를 재사용하는 오 탐지 버그가 있습니다. (그리고 최악의 경우, 그것은 아파치와 같은 장기 실행 프로세스에 선물되었습니다 ....)
Philippe Chaintreuil

1
내 접근 방식에 결함이 있으며 함정이 필요하다는 데 동의합니다. 내 솔루션을 업데이트했습니다. 나는 여전히 외부 의존성을 갖지 않는 것을 선호합니다.
Filidor Wiese

1

프로세스의 잠금을 사용하는 것이 훨씬 강력하고 부실한 출구도 처리합니다. 프로세스가 실행되는 동안 lock_file은 열린 상태로 유지됩니다. 프로세스가 존재하면 (쉘이 죽더라도) 닫힙니다 (쉘로). 나는 이것이 매우 효율적이라는 것을 알았다.

lock_file=/tmp/`basename $0`.lock

if fuser $lock_file > /dev/null 2>&1; then
    echo "WARNING: Other instance of $(basename $0) running."
    exit 1
fi
exec 3> $lock_file 

1

스크립트의 맨 처음 @ oneliner를 사용합니다.

#!/bin/bash

if [[ $(pgrep -afc "$(basename "$0")") -gt "1" ]]; then echo "Another instance of "$0" has already been started!" && exit; fi
.
the_beginning_of_actual_script

프로세스의 상태에 관계없이 메모리에 프로세스가 있는지 확인하는 것이 좋습니다. 그러나 그것은 나를 위해 일을합니다.


0

무리의 길은 갈 길입니다. 스크립트가 갑자기 죽을 때 어떤 일이 발생하는지 생각해보십시오. 무리의 경우에는 무리를 풀어도 문제가되지 않습니다. 또한, 악의적 인 속임수는 스크립트 자체에 무리를 두는 것입니다. 그러나 당연히 권한 문제에 대해 전면적 인 조치를 취할 수 있습니다.


0

빠르고 더러운?

#!/bin/sh

if [ -f sometempfile ]
  echo "Already running... will now terminate."
  exit
else
  touch sometempfile
fi

..do what you want here..

rm sometempfile

7
사용 방법에 따라 문제가 될 수도 있고 아닐 수도 있지만 잠금 테스트와 생성간에 경쟁 조건이 있으므로 두 스크립트를 동시에 시작할 수 있습니다. 하나가 먼저 종료되면 다른 하나는 잠금 파일없이 계속 실행됩니다.
TimB

3
휴대용 쉘 스크립팅에 대해 많은 것을 가르쳐 준 C News는 lock. $$ 파일을 만든 다음 "lock"과 연결하려고 시도했습니다. 그리고 종료했다.
Paul Tomblin

문제가 발생하여 잠금 파일이 삭제되지 않은 경우 여전히 잠금 파일을 수동으로 제거해야한다는 점을 제외하고는 정말 좋은 방법입니다.
Matthew Scharley

2
빠르고 더러운, 그것이 그가 요청한 것입니다 :)
Aupajo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.