쉘 스크립트에서 올바른 잠금?


66

때로는 하나의 쉘 스크립트 인스턴스 만 동시에 실행되고 있는지 확인해야합니다.

예를 들어 자체 잠금 기능을 제공하지 않는 크론을 통해 실행되는 크론 작업 (예 : 기본 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및 친구와 매우 유사한 주제를 구현합니다 .


4
접선으로 그리고 초기 패턴 Good Enough (tm)를 고려할 수있는 다른 사람들을 위해 쉘 코드는 TERM을 트랩하여 에드가있을 때 잠금 파일을 제거해야합니다 kill. 자신의 pid를 만지는 것이 아니라 잠금 파일에 저장하는 것이 좋습니다.
Ulrich Schwarz


@Shawn은 실제로는 크론과 NFS를 언급하지 않습니다.
maxschlepzig

SO에 대한 질문을 관련 : stackoverflow.com/questions/185451/...
maxschlepzig

1
@Ulrich는 매우 뒤늦게, NFS 잠금 파일에 PID를 저장하면 가치가 거의 없습니다. 호스트 이름을 추가해도 실제 프로세스를 확인하는 데 실제로 도움이되지는 않습니다.
roaima

답변:


45

쉘 스크립트에서 잠금을 수행하는 또 다른 방법은 위에서 설명한 경쟁 조건을 방지 할 수 있으며 두 작업이 모두 행 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 방법이 적합해야합니다.


1
아니오, lockrun을 사용하면 NFS 서버가 중단되면 lockf()시스템 호출 에서 최소한 모든 lockrun 호출이 중단 됩니다. 모든 프로세스가 재개되면 모든 프로세스가 재개되지만 하나의 프로세스 만 잠금을 얻습니다. 경쟁 조건이 없습니다. 나는 cronjobs와 같은 문제를 많이 겪지 않습니다. 반대의 경우입니다. 그러나 이것이 당신을 때릴 때의 문제입니다. 많은 고통을 일으킬 수 있습니다.
maxschlepzig

1
이 방법은 안전하고 지금까지 가장 우아하기 때문에이 답변을 수락했습니다. set -o noclobber && echo "$$" > "$lockfile"쉘이 noclobber 옵션을 지원하지 않을 때 안전한 폴백을 얻는 작은 변형을 제안합니다 .
maxschlepzig

3
좋은 대답이지만 잠금을 만든 프로세스가 여전히 존재하도록 lockfile의 값을 'kill -0'으로 설정해야합니다.
Nigel Horne

1
noclobber옵션은 경쟁 조건에 취약 할 수 있습니다. 생각 할만한 음식에 대해서는 mywiki.wooledge.org/BashFAQ/045 를 참조하십시오 .
클린트 Pachl

2
참고 : 사용 noclobber(또는 -Cksh88이 사용하지 않기 때문에 작동하지 않습니다 ksh88에서) O_EXCL를 위해 noclobber. 새로운 쉘을 사용하고 있다면 괜찮을 것입니다.
jrw32982

14

하드 링크를 선호합니다.

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 릴리스를 사용하면 둘 중 어느 것을 사용해도 걱정할 필요가 없습니다.


12

나는 그것이 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

그래도 mkdir()NFS를 통해 (> = 3) 원자로 표준화 되었는지 여부에 대한 정보를 찾을 수 없습니다 .
maxschlepzig

2
@maxschlepzig RFC 1813 은 명시 적으로 원자가되기를 요구 하지 않습니다 mkdir(의 경우 rename). 실제로 일부 구현은 그렇지 않은 것으로 알려져 있습니다. 관련 : GNU arch의 저자가 제공 한 흥미로운 스레드 .
Gilles

8

쉬운 방법은 패키지 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"

5

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

주문이 보장되지는 않습니다. 또한 출력은 끝날 때까지 표시되지 않습니다 (자극!). 그러나 그럼에도 불구하고 잠금 파일과 재시도 및 정리에 대해 걱정하지 않고 동시 실행을 방지하는 가장 간결한 방법입니다.


sem핸들이 제공하는 잠금 기능이 실행 도중에 격추됩니까?
roaima

2

사용 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

1

여기여기에 설명 된대로 명령 행 도구 "flock"을 사용하여 bash 스크립트에서 잠금을 관리합니다 . 나는 무리 맨 페이지 에서이 간단한 방법을 사용하여 서브 쉘에서 일부 명령을 실행했습니다 ...

   (
     flock -n 9
     # ... commands executed under lock ...
   ) 9>/var/lock/mylockfile

이 예에서는 잠금 파일을 얻을 수 없으면 종료 코드 1로 실패합니다. 그러나 무리는 명령을 하위 쉘에서 실행할 필요가없는 방식으로도 사용할 수 있습니다 :-)


3
flock()시스템 호출은 NFS를 통해 작동하지 않습니다 .
maxschlepzig

1
BSD에는 "lockf"라는 비슷한 도구가 있습니다.
dubiousjim

2
@dubiousjim, BSD lockfflock()NFS를 호출 하므로 문제가 있습니다. Btw는 그 동안 fcntl()파일이 NFS 마운트에있을 때 Linux의 flock ()이 다시 돌아가 므로 Linux 전용 NFS 환경 flock()에서는 NFS를 통해 작동합니다.
maxschlepzig

1

파일을 사용하지 마십시오.

스크립트가 다음과 같이 실행되는 경우 :

bash my_script

다음을 사용하여 실행 중인지 감지 할 수 있습니다.

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

흠, PS 검사 코드는 my_script? 다른 인스턴스가 실행중인 경우- running_proc일치하는 두 줄이 포함되어 있지 않습니까? 나는 아이디어를 좋아하지만 물론-다른 사용자가 같은 이름으로 스크립트를 실행할 때 잘못된 결과를 얻을 수 있습니다.
maxschlepzig

3
또한 경쟁 조건이 포함됩니다. 2 개의 인스턴스가 첫 번째 라인을 병렬로 실행하면 아무도 '잠금'을 얻지 않고 둘 다 상태 6으로 종료됩니다. 이것은 일종의 라운드 상호 기아 입니다. Btw, 귀하의 예 $!대신 왜 사용하는지 모르겠습니다 $$.
maxschlepzig

@maxschlepzig는 잘못된 $에 대해 정말 죄송합니다! vs. $$
frogstarr78

스크립트를 실행하는 여러 사용자를 처리하려면 @maxschlepzig -e 인수를 -o 인수에 추가하십시오.
frogstarr78

@maxschlepzig 여러 줄을 방지하기 위해 인수를 grep 또는 추가 "필터"(예 ​​:)로 변경할 수도 있습니다 grep -v $$. 기본적으로 나는 문제에 대한 다른 접근법을 제공하려고했습니다.
frogstarr78

1

실제로 사용하려면 최상위 투표 답변을 사용해야합니다 .

그러나 나는 ps사람들이 그것을 사용하는 것을 계속보고 있기 때문에 여러 가지 파괴되고 반 작업 가능한 접근법 과 그들이 가지고있는 많은주의 에 대해 이야기하고 싶습니다 .

이 답변은 정말 대답은 "왜 사용하지 psgrep쉘에 잠금 처리하기 위해?"

접근 방식 # 1

첫째, 다른 답변 에서 주어진 접근 방식 은 작동하지 않으며 결코 테스트 할 수 없다는 사실에도 불구하고 몇 가지 공감대를 가지고 있습니다.

running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do 
  echo Already locked
  exit 6
fi

구문 오류와 깨진 ps인수를 수정 하고 다음을 얻습니다.

running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
  echo Already locked
  exit 6
fi

이 스크립트는 실행 방법에 관계없이 항상 6을 종료합니다.

로 실행 ./myscript하면 ps출력은 단지 12345 -bash필수 문자열과 일치하지 않으므로 12345 bash ./myscript실패합니다.

로 실행하면 bash myscript상황이 더 흥미로워집니다. 배쉬 프로세스 포크는 파이프 라인을 실행하고, 자식 쉘은 실행 psgrep. 원래 셸과 자식 셸 모두 ps출력에 다음과 같이 표시됩니다 .

25793 bash myscript
25795 bash myscript

예상되는 출력 $$ bash $0이 아니므로 스크립트가 종료됩니다.

부러진 접근법 # 2

이제 깨진 접근법 # 1을 작성한 사용자에게 공평하게, 나는 이것을 처음 시도했을 때 비슷한 것을했습니다.

if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
  echo >&2 "There are other copies of the script running; exiting."
  ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
  exit 1
fi

이것은 거의 작동합니다. 그러나 파이프를 포크로 돌리는 사실은 이것을 버립니다. 따라서 이것도 항상 종료됩니다.

신뢰할 수없는 접근법 # 3

pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
  echo >&2 "There are other copies of this script running; exiting."
  ps -fq "${not_this_process//$'\n'/ }"
  exit 1
fi

이 버전은 명령 행 인수에 현재 스크립트가있는 모든 PID를 먼저 가져온 다음 해당 pidlist를 개별적으로 필터링하여 현재 스크립트의 PID를 생략 함으로써 접근법 # 2에서 파이프 라인 분기 문제점을 방지합니다 .

이것은 다른 프로세스를 제공하지 것은 일치하는 명령 라인을 가지고 ... 작동 할 수 있습니다 $0, 그리고 스크립트를 제공하는 것이 항상이 다음 상대 경로와 절대 경로라고한다면, 후자의 경우는 전자를 통지하지 않습니다 예를 들어, (같은 방식이라고합니다 ).

신뢰할 수없는 접근법 # 4

전체 명령 줄 검사를 건너 뛰면 스크립트가 실제로 실행되고 있음을 나타내지 lsof않고 대신이 스크립트가 열려있는 모든 프로세스를 찾기 위해 검사 할 수 있습니까?

예,이 접근법은 실제로 그렇게 나쁘지 않습니다.

if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
  echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running.  Exiting to avoid conflicts."
  ps >&2 -fq "${otherpids//$'\n'/ }"
  exit 1
fi

물론, 스크립트 사본 이 실행 중이면 새 인스턴스가 정상적으로 시작되고 두 개의 사본이 실행됩니다.

또는 실행중인 스크립트가 수정 된 경우 (예 : Vim 또는 git checkout), 스크립트의 "새"버전은 문제없이 시작됩니다. Vim과 git checkout그 대신 새 파일 (새 inode)이 생성되기 때문입니다. 오래된 것.

그러나 스크립트를 수정하지 않고 복사하지 않으면 이 버전이 좋습니다. 검사에 도달하기 전에 스크립트 파일이 열려 있어야하므로 경쟁 조건이 없습니다.

다른 프로세스에 스크립트 파일이 열려 있으면 여전히 긍정 오류가있을 수 있지만 Vim에서 편집하기 위해 열려있는 경우에도 vim은 실제로 스크립트 파일을 열어 두지 않으므로 오탐 (false positive)이 발생하지 않습니다.

스크립트를 편집하거나 복사 할 수 있습니다하지만 당신이 얻을 것이기 때문에 거짓이 방법을 사용하지 않는 기억 악재가 빔으로 편집하는 오탐 (false positive)이 종류의 문제가되지해야합니다 제공하지 않습니다 너무 사실 - 한 번에 여러 인스턴스가 실행 즉, 당신에게. 방법 # 3이 때문에,하지만 그것을 언급 않습니다 당신은 빔 오픈 스크립트가있는 경우 (즉, 시작하는 것을 거부) 잘못된 반응을 제공합니다.

그럼 어떻게해야합니까?

이 질문에 대한 최고의 투표 대답은 좋은 고체 접근 방식을 제공합니다.

아마도 더 좋은 것을 쓸 수는 있지만 위의 모든 접근 방식의 모든 문제와주의를 이해하지 못하면 모든 것을 피하는 잠금 방법을 작성하지 않을 것입니다.



0

다음은 기계의 모든 작업에 대한 경쟁 조건을 쉽게 처리하기 위해 서버에 추가하는 내용입니다. Tim Kennedy의 게시물과 비슷하지만이 방법을 사용하면 필요한 각 bash 스크립트에 하나의 행만 추가하면 레이스 처리가 가능합니다.

아래 내용을 / opt / racechecker / racechecker에 넣으십시오.

ZPROGRAMNAME=$(readlink -f $0)
EZPROGRAMNAME=`echo $ZPROGRAMNAME | sed 's/\//_/g'`
EZMAIL="/usr/bin/mail"
EZCAT="/bin/cat"

if  [ -n "$EZPROGRAMNAME" ] ;then
        EZPIDFILE=/tmp/$EZPROGRAMNAME.pid
        if [ -e "$EZPIDFILE" ] ;then
                EZPID=$($EZCAT $EZPIDFILE)
                echo "" | $EZMAIL -s "$ZPROGRAMNAME already running with pid $EZPID"  alarms@someemail.com >>/dev/null
                exit -1
        fi
        echo $$ >> $EZPIDFILE
        function finish {
          rm  $EZPIDFILE
        }
        trap finish EXIT
fi

사용 방법은 다음과 같습니다. shebang 다음 행을 참고하십시오.

     #/bin/bash
     . /opt/racechecker/racechecker
     echo "script are running"
     sleep 120

작동 방식은 기본 bashscript 파일 이름을 파악하고 "/ tmp"아래에 pidfile을 작성하는 것입니다. 또한 종료 신호에 리스너를 추가합니다. 리스너는 기본 스크립트가 올바르게 완료되면 pidfile을 제거합니다.

대신 인스턴스가 시작될 때 pidfile이 존재하면 두 번째 if 문 안에 코드를 포함하는 if 문이 실행됩니다. 이 경우 나는 이것이 일어날 때 알람 메일을 시작하기로 결정했습니다.

스크립트가 충돌하면 어떻게됩니까

추가 연습은 충돌을 처리하는 것입니다. 이상적으로 메인 스크립트가 어떤 이유로 충돌하더라도 pidfile을 제거해야합니다. 위의 버전에서는이 작업이 수행되지 않습니다. 즉, 스크립트가 충돌하면 기능을 복원하기 위해 pidfile을 수동으로 제거해야합니다.

시스템 충돌시

pidfile / lockfile을 예를 들어 / tmp에 저장하는 것이 좋습니다. 이렇게하면 pidfile이 부팅시 항상 삭제되므로 시스템 충돌 후 스크립트가 계속 실행됩니다.


Tim Kennedy의 ansatz와 달리 스크립트에는 경쟁 조건이 포함되어 있습니다. PIDFILE의 존재 및 조건부 작성이 원 자성 조작에서 수행되지 않았기 때문입니다.
maxschlepzig 2016 년

그것에 +1! 이를 고려하여 스크립트를 수정하겠습니다.
ziggestardust 2016 년

-2

내 스크립트 확인 ...

당신은 할 수있다 사랑 을 ....

[rambabu@Server01 ~]$ sh Prevent_cron-OR-Script_against_parallel_run.sh
Parallel RUN Enabled
Now running
Task completed in Parallel RUN...
[rambabu@Server01 ~]$ cat Prevent_cron-OR-Script_against_parallel_run.sh
#!/bin/bash
#Created by RambabuKella
#Date : 12-12-2013

#LOCK file name
Parallel_RUN="yes"
#Parallel_RUN="no"
PS_GREP=0
LOCK=/var/tmp/mylock_`whoami`_"$0"
#Checking for the process
PS_GREP=`ps -ef |grep "sh $0" |grep -v grep|wc -l`
if [ "$Parallel_RUN" == "no" ] ;then
echo "Parallel RUN Disabled"

 if [ -f $LOCK ] || [ $PS_GREP -gt 2   ] ;then
        echo -e "\nJob is already running OR LOCK file exists. "
        echo -e "\nDetail are : "
        ps -ef |grep  "$0" |grep -v grep
        cat "$LOCK"
  exit 6
 fi
echo -e "LOCK file \" $LOCK \" created on : `date +%F-%H-%M` ." &> $LOCK
# do some work
echo "Now running"
echo "Task completed on with single RUN ..."
#done

rm -v $LOCK 2>/dev/null
exit 0
else

echo "Parallel RUN Enabled"

# do some work
echo "Now running"
echo "Task completed in Parallel RUN..."
#done

exit 0
fi
echo "some thing wrong"
exit 2
[rambabu@Server01 ~]$

-3

'flocktest'라는 스크립트에서 다음 솔루션을 제공합니다.

#!/bin/bash
export LOGFILE=`basename $0`.logfile
logit () {
echo "$1" >>$LOGFILE
}
PROGPATH=$0
(
flock -x -n 257
(($?)) && logit "'$PROGPATH' is already running!" && exit 0
logit "'$PROGPATH', proc($$): sleeping 30 seconds"
sleep 30
)257<$PROGPATH
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.