도구가 이미 실행 중이지만 현재 사용자에게만 있는지 감지


8

지금까지 나는

pidof -o %PPID -x "my-tool"

결국 실행중인 my-tool 인스턴스의 pid를 감지합니다.

이것은 실행 가능한 bash 스크립트 인 my-tool 파일의 짧은 버전입니다.

#!/bin/bash 

if pidof -o %PPID -x "my-tool"; then
   echo "Already running"
   exit 1
fi

 ... if not running go on 

그러나 이제는 사용자 당 하나의 인스턴스와 머신 당 여러 인스턴스 를 허용해야 하므로 같은 시점에 100 개의 my-tool을 실행할 수 있지만 사용자 당 1 개만 가능합니다.

싱글 톤과 같은 것을 만들려면 테스트가 필요합니다. 도구가 시작되고 실행중인 다른 인스턴스가 있으면 자체적으로 닫힙니다.

간단히 말해서 : bash 스크립트가 현재 사용자에 대해 이미 실행 중인지 감지 할 수 있어야 하며이 경우 종료해야합니다.

어떻게 ?


당신은 사용하지 말아야 pidof더 나은 도구가 거짓말이다pgrep
고양이

답변:


12

pgrep대신 사용하십시오 :

pgrep -cxu $USER -f my-tool

사용되는 옵션은 다음과 같습니다.

   -c, --count
          Suppress  normal  output; instead print a count of matching pro
          cesses.  When count does not match anything, e.g. returns  zero,
          the command will return non-zero value.
   -x, --exact
          Only match processes whose names (or command line if -f is spec
          ified) exactly match the pattern.
   -u, --euid euid,...
          Only match processes whose effective user ID is listed.   Either
          the numerical or symbolical value may be used.

이미 실행 중인지 확인하는 bash 스크립트에서 이것을 사용하려면을 사용할 수 있습니다 $0. 이것은 현재 스크립트 (예 :)의 경로로 확장 /home/username/bin/foo.sh되지만 필요합니다 foo.sh. 그것을 얻으려면, 우리는 마지막에 모든 것을 제거 할 수 있습니다 /사용 배쉬의 문자열 조작 도구 : ${0##*/}. 이것은 우리가 다음과 같은 것을 할 수 있음을 의미합니다.

## If there are more than 1 instances of the current script run
## by this user
if [[ $(pgrep -cxu "$USER" "${0##*/}") -gt 1 ]];
then
        echo "Script already running, exiting."
        exit
fi

이를 위해 잠금 파일 사용을 고려할 수도 있습니다.

## If the lock file exists
if [ -e /tmp/$USER.foo.lock ]; then
    ## Check if the PID in the lockfile is a running instance
    ## of foo.sh to guard against crashed scripts
    if ps $(cat /tmp/$USER.foo.lock) | grep foo.sh >/dev/null; then
        echo "Script foo.sh is already running, exiting"
        exit
    else
        echo "Lockfile contains a stale PID, continuing"
        rm /tmp/$USER.foo.lock 
    fi
fi
## Create the lockfile by printing the script's PID into it
echo $$ > /tmp/$USER.foo.lock

## Rest of the script here

## At the end, delete the lockfile
rm /tmp/$USER.foo.lock


1
touch /tmp/$USER.foo.lock프로세스의 PID를 사용하는 대신 echo $$ >/tmp/$USER.foo.lock이러한 프로세스가 실제로 존재하는지 테스트하기 위해 로직을 포함시킬 수 있습니다.
Monty Harder

@MontyHarder는 정말 좋은 제안입니다. 답변이 수정되었습니다. 감사합니다.
terdon

@terdon은 모바일에 문제가 있었으며 다음 순간에 그 의견을 삭제했습니다. 나는 $(< pidfile)대신에 의미 했다 $(cat pidfile).
sdkks

7

pgrep특정 사용자가 프로세스를 실행중인 경우 fo 찾기 를 사용 하여 사용자가 아직 실행하지 않은 경우 프로세스를 시작할 수 있습니다.

#!/bin/bash
if pgrep -u "$USER" my-tool &>/dev/null; then
    echo 'You already have my-tool running'
else
    /path/to/my_tool
fi

환경 변수 $USER는 현재 로그인 한 사용자, 즉 스크립트를 실행하는 사용자로 확장됩니다. 우리 my-tool는 실행 중인지 아닌지에만 관심이 있기 때문에, if구성 과 함께 직접 종료 상태를 사용하는 것으로 충분합니다.

이 스크립트를 시작하기위한 랩퍼로 my-tool사용하고 사용자가이를 사용하도록하거나 이름을 my-tool바꾸고 원본 my-tool의 이름을 다른 것으로 바꾸십시오 (스크립트 내부의 이름도 변경).


래퍼, 긴 역사를 만들 수 없습니다 ... 현재 프로세스 PID를 어떻게 제외시킬 수 있습니까?
realtebo

@realtebo ummm..PID 의미를 제외 하시겠습니까?
heemayl

2

이 스 니펫으로 사용해보십시오.

#!/bin/bash
MyProcessName=$(ps -p $$ -o args=)
Mypid=$$
AllPids=$(pgrep -fu "$(whoami)" "$MyProcessName")
AllPids=$(tr "\n" ' ' <<<"$AllPids")
Pids=$(sed "s/$Mypid//" <<<"$AllPids")
echo "$$: Instances including itself: $AllPids"
echo "$$: Instances different from itself: $Pids"

pgrep|tr동일한 이름의 쉘에 포크되므로 작성하지 않는 것이 중요합니다 .


2

한 번에 하나의 사본 만 실행되도록 무리에서 실행할 명령을 랩하십시오. 각 사용자가 자신의 잠금 파일을 갖도록 사용자의 홈 디렉토리 트리에 저장된 lock_file을 사용하십시오. 예를 들면 다음과 같습니다.

lockfile = "~/lockfile"
(
 if flock -n 200; then
    command
 else
    echo "Could not get lock $lock_file
 fi
) 200>$lock_file

'command'는 모든 bash 명령 또는 스크립트 일 수 있습니다.

man flock 사용법의 예를 제공


정말로, 나는 flock명령을 전혀
몰랐다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.