쉘 스크립트 - 내 프로세스를 제외한 이름으로 모든 프로세스 종료

쉘 스크립트 - 내 프로세스를 제외한 이름으로 모든 프로세스 종료

test.sh쉘 스크립트가 실행 중 입니다 .

test.sh이 스크립트의 시작 부분에서 이전 스크립트가 실행 중이라면 먼저 해당 스크립트를 종료하고 싶습니다 .

종료하면 test.sh최신 프로세스도 모두 종료됩니다.

내가 할 수 있는 쉬운 방법이 있나요?

답변1

#!/bin/sh

term_handler () {
    if [ "$ok_to_exit" -eq 1 ]; then
        echo 'exiting'
        exit
    else
        echo 'refusing to exit'
    fi
}

trap term_handler TERM

ok_to_exit=0
pkill -f test.sh
ok_to_exit=1

while true; do
    echo 'working...'
    sleep 2
done

이 스크립트(아래에 더 간단한 버전이 있음)는 신호가 수신될 term_handler때 스크립트를 종료 하는 신호 처리기를 설치합니다.TERM만약에변수 ok_to_exit의 값은 입니다 1.

수행 중인 작업의 일부 형태를 시뮬레이션하는 루프가 스크립트 본문에 있습니다. 중요한 것은 호출하기 전에 pkill(이것을 명령으로 변경할 수 있음 killall) ok_to_exit로 설정 0한 다음 즉시 로 설정한다는 것입니다 1.

일치하는 모든 프로세스가 TERM신호를 받으면 자체적으로 신호를 받지만 종료를 거부합니다. 다른 일치 프로세스,완전히 동일한 상태가 아닌 경우(동시에 여러 번 스크립트를 시작하면 이런 일이 발생할 수 있습니다.) 종료됩니다.

실행하면 스크립트가 출력됩니다.

refusing to exit
working...
working...
working...

스크립트의 다른 복사본이 시작되면 출력된 exiting다음 종료됩니다.

동일한 스크립트의 더 간단한 버전:

#!/bin/sh

trap '' TERM
pkill -f test.sh
trap - TERM

while true; do
    echo 'working...'
    sleep 2
done

이것은 단순히소홀히 하다TERM호출 중에 신호를 호출한 pkill다음 계속하기 전에 기본 신호 처리기를 복원하십시오.

답변2

신호 처리기 사용을 피하는 좋은 방법은 자신의 프로세스를 제외한 모든 프로세스에 신호를 보내는 것입니다.

for pid in $(pgrep ${0##*/}); do
    if [[ $pid -ne $$ ]]; then
        kill -s TERM $pid
    fi
done

Bash에 익숙하지 않은 경우 "/path/to/test.sh"가 "test.sh"가 되도록 ${0##*/}기본 이름(스크립트가 호출하는 이름)이 제공됩니다 .$0

답변3

세 개 이상의 인스턴스를 시작하는 데 약간의 문제가 있지만 pgrep다음과 같이 /를 사용할 수 있습니다.pkill

#!/bin/sh

while [ "$(pgrep -c -f test.sh)" -gt 1 ]
do
  pkill --oldest -f test.sh
done

# rest of your script

프로세스 이름 자체와 더 정확하게 일치하도록 "test.sh" 매개변수를 조정하세요!

몇 가지 예를 들어보세요:

/bin/sh ./test.sh

또는

/bin/sh /full/path/to/test.sh

또는

/bin/bash ./test.sh

또는

sh test.sh

...그래서 실수로 다른 것과 일치하지 않게 됩니다.

답변4

만약에모두당신의 처형test.sh 언제나이와 같은 관리인 확인을 통해 다음을 수행할 수 있습니다.

pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] && kill $pid

위의 줄은 호출 방법에 관계없이 현재 실행이 아닌 한 가장 오래된 실행만 종료합니다.

그러나 이전 실행에서 누락된 검사가 없는지 절대적으로 확인하려는 경우에는 위 줄을 while다음과 같은 루프에 넣을 수 있습니다.

while pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] ; do
    kill $pid
done

위에서 죽여라어느이전 실행 test.sh(호출됨)

필요에 따라 명령의 특정 리터럴 매개변수도 고려하는 선택 기준이 필요할 수 있습니다.

다음과 같이 확인하려는 매개변수를 큰따옴표로 묶어 이를 수행할 수 있습니다.

(pgrep참고: 위 코드에 사용된 부분 만 표시했습니다.)

pgrep -o -f "/test.sh +arg1 +arg2 *$"

추가 +합계는 *$ 이러한 매개변수와 정확히 일치해야 합니다. (이 예에서는 리터럴 문자열 arg1arg2).

변수를 전달할 수도 있습니다. 예를 들어 이상적인 변형은 현재 실행과 동일한 매개변수를 사용하여 실행된 이전 실행만 종료하는 것일 수 있습니다.

pgrep -o -f "/test.sh +${*} *$"

이는 ${*}현재 실행의 모든 ​​매개변수로 변환됩니다.

기본적으로 큰따옴표 안의 문자열은 유효한 정규식일 수 있습니다. 이는 종료하려는 실행을 정확하게 일치시키는 데 도움이 되며, 이는 외부 프로세스 종료를 방지하는 데 매우 중요합니다.

관련 정보