다음과 같은 Bash 스크립트가 있는 경우:
function repeat {
while :; do
echo repeating; sleep 1
done
}
repeat &
echo running once
running once
한 번 인쇄되지만 repeat
포크는 영원히 존재하여 무한히 인쇄됩니다.
repeat
이를 생성한 스크립트가 종료된 후에도 계속 실행되지 않도록 하려면 어떻게 해야 합니까 ?
bash -c
새 인터프리터를 명시적으로 인스턴스화하면 상위 프로세스가 사라졌기 때문에 강제로 종료될 것이라고 생각했지만 고아 프로세스가 init
PID 1에 의해 채택된 것 같습니다.
다른 파일로 이것을 테스트하십시오.
# repeat.bash
while :; do echo repeating; sleep 1; done
# fork.bash
bash -c "./repeat.bash & echo an exiting command"
실행하면 계속해서 백그라운드에서 계속 실행 ./fork.bash
됩니다 .repeat.bash
간단하고 게으른 해결책은 다음 줄을 추가하는 것입니다 fork.bash
.
pkill repeat.bash
하지만 다른 중요한 프로세스에서 이 이름을 사용하지 않는 것이 좋습니다. 그렇지 않으면 이름도 지워집니다.
백그라운드 작업을 생성한 스크립트(또는 프로세스)가 종료될 때 종료되어야 하는 분기된 셸에서 백그라운드 작업을 처리하는 더 좋고 수용 가능한 방법이 있는지 궁금합니다.
모든 프로세스에 대해 동일한 이름을 맹목적으로 사용하는 것보다 더 좋은 방법이 없다면
pkilling
네트워크 서버와 같은 것으로 실행되는 중복 작업을 어떻게 처리하여 종료해야 합니까 ?cron
스크립트가git
저장소에 있고 코드가 변경 없이 자체 포함되어야 하므로 작업을 피하고 싶습니다/etc/
.
답변1
스크립트가 종료되기 전에 백그라운드 프로세스가 종료됩니다.
trap '[ "$pid" ] && kill "$pid"' EXIT
function repeat {
while :; do
echo repeating; sleep 1
done
}
repeat &
pid=$!
echo running once
어떻게 작동하나요?
trap '[ "$pid" ] && kill "$pid"' EXIT
이것은덫. 스크립트가 종료되려고 할 때마다 작은따옴표로 묶인 명령이 실행됩니다. 이 명령은 쉘 변수에
pid
널이 아닌 값이 지정되었는지 확인합니다. 있는 경우 해당 프로세스와 관련된 프로세스가pid
종료됩니다.pid=$!
이는 이전 백그라운드 command()의 프로세스 ID를
repeat &
쉘 변수에 저장합니다pid
.
개선하다
~처럼패트릭댓글에서 지적했듯이 스크립트가 종료될 가능성이 있습니다.뒤쪽에백그라운드 프로세스가 시작되지만앞으로변수가 pid
설정되었습니다. 다음 코드를 사용하여 이 상황을 처리할 수 있습니다.
my_exit() {
[ "$racing" ] && pid=$!
[ "$pid" ] && kill "$pid"
}
trap my_exit EXIT
function repeat {
while :; do
echo repeating; sleep 1
done
}
racing=Y
repeat &
pid=$!
racing=
echo running once
답변2
쉘에는 종료 시 명령을 종료하도록 쉘에 지시하는 명령이 tcsh
있습니다 .hup
hup mycommand...
tcsh
이는 기능을 지원하지 않기 때문에 기능 실행에 도움이 되지 않습니다 .
에서 zsh
작업 제어가 활성화되면 모든 백그라운드 작업에 대해 기본적으로 이 작업이 수행됩니다.
$ zsh -c 'set -m; sleep 2 &'; ps
[1] 23672
zsh:1: warning: 1 jobs SIGHUPed
그러나 스크립트에서 작업 제어를 활성화하면 부작용이 발생할 수 있습니다.
bash
이 작업을 수행하는 것도 가능하지만 대화형으로만(스크립트에서 -i를 사용하여 호출해도 이 작업을 수행할 수 있음) 쉘에 로그인한 경우에만(!?) 가능합니다. 그리고 이 옵션을 활성화해야 합니다 huponexit
. 그래서:
bash -O huponexit -lic 'sleep 2 &'
하지만 이는 부작용이 많기 때문에 아마도 좋은 생각은 아닐 것입니다.
또 다른 옵션 zsh
은 종료 시 실행 중인 알려진 모든 하위 프로세스를 종료하는 것입니다. 어떤 경우에도 손자 프로세스에 대해 쉽게 알 수 없습니다(항상 종료하고 싶지도 않습니다). 연관 배열에서 사용 가능하게 zsh
만드세요 :$jobstates
TRAPEXIT() kill -s HUP ${${jobstates[(R)running:*]/#*:/}/%=*/}
trap exit INT HUP TERM
다른 쉘은 하위 프로세스 목록을 공개하지 않지만 ppid를 사용하여 프로세스를 종료할 수 있습니다 $$
. 예를 들면 다음과 같습니다.
trap 'pkill -HUP -P "$$"' EXIT INT HUP TERM