Bash 스크립트의 인스턴스가 1개만 실행되도록 하는 가장 좋은 방법은 무엇입니까?
Linux에서 Bash를 실행한다고 가정했을 때 특정 스크립트의 인스턴스를 하나만 실행할 수 있는 가장 단순하고 최선의 방법은 무엇입니까?
지금 하고 있는 일:
ps -C script.name.sh > /dev/null 2>&1 || ./script.name.sh
단, 몇 가지 문제가 있습니다.
- 체크가 스크립트 밖에 있다
- 다른 어카운트에서 같은 스크립트를 실행할 수 없습니다(가끔은 하고 싶은 경우도 있습니다.
-C
프로세스 의 첫 합니다.
물론 PID 파일 처리도 직접 쓸 수 있지만 간단한 방법이 있을 것 같습니다.
권장 잠금 기능은 오랫동안 사용되어 왔으며 bash 스크립트에서 사용할 수 있습니다.는 단순한 것을 flock
:util-linux[-ng]
)의 개요lockfile
:procmail
의 트랩에 기억해 주세요(「spec 「스펙」 == 「스펙」 == 「스펙」EXIT
★★★★★★★★★★★★★★★★★」0
특정 신호를 트래핑하는 것은 불필요한 것입니다).
2009년에 나는 잠글 수 있는 스크립트 보일러 플레이트를 발매했다(원래는 내 위키페이지에서 입수할 수 있었지만, 현재는 지스트로 입수할 수 있다).이를 사용자당 1인스턴스로 변환하는 것은 간단한 일입니다.또한 잠금 또는 동기화가 필요한 다른 시나리오의 스크립트를 쉽게 작성할 수도 있습니다.
여기 편의를 위해 언급한 보일러판이 있습니다.
#!/bin/bash
# SPDX-License-Identifier: MIT
## Copyright (C) 2009 Przemyslaw Pawelczyk <przemoc@gmail.com>
##
## This script is licensed under the terms of the MIT license.
## https://opensource.org/licenses/MIT
#
# Lockable script boilerplate
### HEADER ###
LOCKFILE="/var/lock/`basename $0`"
LOCKFD=99
# PRIVATE
_lock() { flock -$1 $LOCKFD; }
_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; }
_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; }
# ON START
_prepare_locking
# PUBLIC
exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail
exlock() { _lock x; } # obtain an exclusive lock
shlock() { _lock s; } # obtain a shared lock
unlock() { _lock u; } # drop a lock
### BEGIN OF SCRIPT ###
# Simplest example is avoiding running multiple instances of script.
exlock_now || exit 1
# Remember! Lock file is removed when one of the scripts exits and it is
# the only script holding the lock or lock is not acquired at all.
간에 를 사용할 수 .lockfile
if하여 메시지 후 종료합니다.잠금을 획득한 경우 계속 진행하거나 메시지를 표시한 후 종료합니다.
예를 들어 다음과 같습니다.
[Terminal #1] $ lockfile -r 0 /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] lockfile: Sorry, giving up on "/tmp/the.lock"
[Terminal #1] $ rm -f /tmp/the.lock
[Terminal #1] $
[Terminal #2] $ lockfile -r 0 /tmp/the.lock
[Terminal #2] $
★★★ /tmp/the.lock
이치노실행할 수 있는 유일한 사용자가 됩니다.끝나면 잠금장치만 해제하면 됩니다.스크립트 형식에서는 다음과 같습니다.
#!/bin/bash
lockfile -r 0 /tmp/the.lock || exit 1
# Do stuff here
rm -f /tmp/the.lock
생각에는flock
아마도 가장 쉽고 기억에 남는 변종일 것입니다.cron 작업에서 DVD와 CD를 자동 인코딩하는 데 사용합니다.
# try to run a command, but fail immediately if it's already running
flock -n /var/lock/myjob.lock my_bash_command
-w
시간 초과 또는 생략 옵션을 사용하여 잠금이 해제될 때까지 기다립니다.마지막으로 man 페이지에는 여러 명령어에 대한 좋은 예가 표시됩니다.
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
bash bash 를 합니다.set -o noclobber
옵션을 지정하고 공통 파일을 덮어씁니다.
프렌들리'은 '배시 프렌들리'를 할 때 합니다.flock
사용할 수 없거나 해당되지 않습니다.
간단한 예
if ! (set -o noclobber ; echo > /tmp/global.lock) ; then
exit 1 # the global.lock already exists
fi
# ... remainder of script ...
보다 긴 예
에서는 ''가 .global.lock
파일이지만 시간이 너무 오래 걸리면 타임아웃됩니다.
function lockfile_waithold()
{
declare -ir time_beg=$(date '+%s')
declare -ir time_max=7140 # 7140 s = 1 hour 59 min.
# poll for lock file up to ${time_max}s
# put debugging info in lock file in case of issues ...
while ! \
(set -o noclobber ; \
echo -e "DATE:$(date)\nUSER:$(whoami)\nPID:$$" > /tmp/global.lock \
) 2>/dev/null
do
if [ $(($(date '+%s') - ${time_beg})) -gt ${time_max} ] ; then
echo "Error: waited too long for lock file /tmp/global.lock" 1>&2
return 1
fi
sleep 1
done
return 0
}
function lockfile_release()
{
rm -f /tmp/global.lock
}
if ! lockfile_waithold ; then
exit 1
fi
trap lockfile_release EXIT
# ... remainder of script ...
이 기술은 장기간 실행되는 Ubuntu 16 호스트에서 안정적으로 작동했습니다.호스트는 동일한 시스템 전체의 "잠금" 파일을 사용하여 작업을 조정하는 bash 스크립트의 많은 인스턴스를 정기적으로 대기열에 넣습니다.
(이것은 나중에 알게 된 @Barry Kelly의 투고와 유사합니다).
한 줄짜리 견고한 솔루션이 있는지 잘 모르기 때문에 독자적으로 솔루션을 구축하게 될 수도 있습니다.
잠금 파일은 불완전하지만 'ps | grep | grep - v' 파이프라인을 사용하는 것보다 덜합니다.
그렇다고 해도 프로세스 제어는 스크립트와 별도로 해 두는 것을 검토해 주십시오.시작 스크립트를 준비해 주세요.또는 적어도 다른 파일에 보관되어 있는 함수에 대해서는, 발신자 스크립트로 다음의 항목을 설정할 수 있도록 합니다.
. my_script_control.ksh
# Function exits if cannot start due to lockfile or prior running instance.
my_start_me_up lockfile_name;
trap "rm -f $lockfile_name; exit" 0 2 3 15
제어 로직을 필요로 하는 각 스크립트에 있습니다.이 트랩을 사용하면 발신자가 종료할 때 잠금파일이 삭제되므로 스크립트의 각 종료 포인트에서 이를 코드화할 필요가 없습니다.
별도의 제어 스크립트를 사용하면 오래된 로그 파일을 삭제하고 잠금 파일이 현재 실행 중인 스크립트의 인스턴스와 올바르게 관련되어 있는지 확인하며 실행 중인 프로세스를 종료하는 옵션을 제공하는 등 Edge 케이스의 건전성을 확인할 수 있습니다.GREP에서 를 사용할 .ps
이치노ps-blockp에 관련된 할 수 .프로세스에 대한 정보(user, pid 등)를 포함하기 위해 어떤 방법으로든 잠금 파일의 이름을 지정할 수 있습니다.이러한 이름을 나중에 스크립트 호출을 통해 잠금 파일을 작성한 프로세스가 아직 존재하는지 여부를 판단할 수 있습니다.
procmail 패키지의 의존관계에서 이것을 발견했습니다.
apt install liblockfile-bin
방법: " " " " "dotlockfile -l file.lock
file.lock이 생성됩니다.
해제 : " " " " " " "dotlockfile -u file.lock
하여 패키지 파일/명령어를 합니다: 명명명명 use use / this this this use use use use use 。 dpkg-query -L liblockfile-bin
첫 번째 테스트 예시
[[ $(lsof -t $0| wc -l) > 1 ]] && echo "At least one of $0 is running"
두 번째 테스트 예시
currsh=$0
currpid=$$
runpid=$(lsof -t $currsh| paste -s -d " ")
if [[ $runpid == $currpid ]]
then
sleep 11111111111111111
else
echo -e "\nPID($runpid)($currpid) ::: At least one of \"$currsh\" is running !!!\n"
false
exit 1
fi
설명.
"lsof - t" : "$0" 이라는 이름의 현재 실행 중인 스크립트의 모든 피드를 나열합니다.
명령어 "lsof"에는 두 가지 이점이 있습니다.
- vim은 ".file.swp"와 같은 매핑 파일을 편집하므로 vim과 같은 편집기에서 편집 중인 pids는 무시하십시오.
- 현재 실행 중인 셸 스크립트에서 분기된 pids를 무시합니다. 대부분의 "grep" 파생 명령에서는 이를 달성할 수 없습니다.현재 프로세스 포킹 상태에 대한 자세한 내용을 보려면 "pstree -pH pidnum" 명령을 사용합니다.
chpst(runit의 일부)도 참조할 것을 권장합니다.
chpst -L /tmp/your-lockfile.loc ./script.name.sh
Ubuntu/Debian Distros는 당신이 설명한 것과 같은 목적을 위한 도구를 가지고 있습니다.start/stop 스크립트의 기술 방법에 대해서는, /etc/init.d/skeleton 도 참조해 주세요.
--노아
한 줄의 궁극적인 솔루션:
[ "$(pgrep -fn $0)" -ne "$(pgrep -fo $0)" ] && echo "At least 2 copies of $0 are running"
저도 같은 문제가 있어서 lock file을 사용하는 템플릿, 프로세스 ID 번호를 저장하는 pid 파일, 그리고 pid 파일을 생각해 냈습니다.kill -0 $(cat $pid_file)
중단된 스크립트가 다음 실행을 중지하지 않도록 하려면 선택하십시오.그러면 lockfile 및 pid 파일이 존재하는 /tmp에 foobar-$USERID 폴더가 생성됩니다.
하다 보면 하거나 다른 할 수 .alertRunningPS
.
#!/bin/bash
user_id_num=$(id -u)
pid_file="/tmp/foobar-$user_id_num/foobar-$user_id_num.pid"
lock_file="/tmp/foobar-$user_id_num/running.lock"
ps_id=$$
function alertRunningPS () {
local PID=$(cat "$pid_file" 2> /dev/null)
echo "Lockfile present. ps id file: $PID"
echo "Checking if process is actually running or something left over from crash..."
if kill -0 $PID 2> /dev/null; then
echo "Already running, exiting"
exit 1
else
echo "Not running, removing lock and continuing"
rm -f "$lock_file"
lockfile -r 0 "$lock_file"
fi
}
echo "Hello, checking some stuff before locking stuff"
# Lock further operations to one process
mkdir -p /tmp/foobar-$user_id_num
lockfile -r 0 "$lock_file" || alertRunningPS
# Do stuff here
echo -n $ps_id > "$pid_file"
echo "Running stuff in ONE ps"
sleep 30s
rm -f "$lock_file"
rm -f "$pid_file"
exit 0
"시스템당 스크립트 1부"를 처리하는 매우 간단한 방법을 찾았습니다.단, 많은 계정에서 스크립트의 여러 복사본을 실행할 수 없습니다(표준 Linux).
솔루션:
대본의 첫머리에서 저는 다음과 같이 말했습니다.
pidof -s -o '%PPID' -x $( basename $0 ) > /dev/null 2>&1 && exit
PIDOF는 다음과 같은 방식으로 잘 작동합니다.
ps -C ...
- 가 할 가 없다
grep -v grep
와 유사한 것 (「」)
또한 잠금 파일에 의존하지 않습니다. 잠금 파일에 대한 릴레이는 오래된 잠금 파일에 대한 처리를 추가해야 한다는 것을 의미하기 때문에 매우 유용합니다. 이 작업은 그다지 복잡하지 않지만 피할 수 있다면 왜 안 될까요?
'실행 중인 사용자 1인당 스크립트 1부' 체크에 대해서는 이렇게 썼지만 그다지 만족스럽지는 않습니다.
(
pidof -s -o '%PPID' -x $( basename $0 ) | tr ' ' '\n'
ps xo pid= | tr -cd '[0-9\n]'
) | sort | uniq -d
출력을 확인합니다(비어 있는 경우). 같은 사용자가 보낸 스크립트의 복사본이 없습니다.
이게 저희의 표준 비트입니다.잠금 파일을 정리하지 않고 스크립트가 소멸된 상태에서 복구할 수 있습니다.
정상적으로 동작하고 있는 경우는, 프로세스 ID 를 록 파일에 씁니다.실행 시작 시 잠금 파일이 발견되면 잠금 파일에서 프로세스 ID를 읽고 프로세스가 존재하는지 확인합니다.프로세스가 존재하지 않는 경우 오래된 잠금 파일을 삭제하고 계속 진행합니다.또한 잠금 파일이 존재하며 프로세스가 아직 실행 중인 경우에만 종료됩니다.그리고 나갈 때 메시지를 씁니다.
# lock to ensure we don't get two copies of the same job
script_name="myscript.sh"
lock="/var/run/${script_name}.pid"
if [[ -e "${lock}" ]]; then
pid=$(cat ${lock})
if [[ -e /proc/${pid} ]]; then
echo "${script_name}: Process ${pid} is still running, exiting."
exit 1
else
# Clean up previous lock file
rm -f ${lock}
fi
fi
trap "rm -f ${lock}; exit $?" INT TERM EXIT
# write $$ (PID) to the lock file
echo "$$" > ${lock}
스크립트를 사용하여 다음을 수행합니다.
ps -ef | grep $0 | grep $(whoami)
언급URL : https://stackoverflow.com/questions/1715137/what-is-the-best-way-to-ensure-only-one-instance-of-a-bash-script-is-running
'programing' 카테고리의 다른 글
디렉토리의 모든 파일 및 폴더 삭제 (0) | 2023.04.17 |
---|---|
리모트 브랜치가 삭제된 오리진에서 가져오시겠습니까? (0) | 2023.04.17 |
SQL Server 문자열에서 모든 공간 제거 (0) | 2023.04.17 |
SQL Server에 LastIndexOf가 있습니까? (0) | 2023.04.17 |
선택적 메서드를 사용하여 프로토콜을 만드는 방법은 무엇입니까? (0) | 2023.04.17 |