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 *$"
추가 +
합계는 *$
이러한 매개변수와 정확히 일치해야 합니다. (이 예에서는 리터럴 문자열 arg1
과arg2
).
변수를 전달할 수도 있습니다. 예를 들어 이상적인 변형은 현재 실행과 동일한 매개변수를 사용하여 실행된 이전 실행만 종료하는 것일 수 있습니다.
pgrep -o -f "/test.sh +${*} *$"
이는 ${*}
현재 실행의 모든 매개변수로 변환됩니다.
기본적으로 큰따옴표 안의 문자열은 유효한 정규식일 수 있습니다. 이는 종료하려는 실행을 정확하게 일치시키는 데 도움이 되며, 이는 외부 프로세스 종료를 방지하는 데 매우 중요합니다.