답변:
시험:
#!/bin/bash
_term() {
echo "Caught SIGTERM signal!"
kill -TERM "$child" 2>/dev/null
}
trap _term SIGTERM
echo "Doing some initial work...";
/bin/start/main/server --nodaemon &
child=$!
wait "$child"
일반적으로 bash
자식 프로세스가 실행되는 동안 신호를 무시합니다. 로 서버 시작 &
과 함께, 쉘의 작업 제어 시스템에 의지 배경을 $!
서버의 PID를 잡고 (함께 사용되는 wait
및 kill
). wait
그런 다음 호출 하면 지정된 PID (서버)로 작업이 완료 되거나 신호가 발생할 때까지 기다립니다 .
쉘이 수신 SIGTERM
(또는 서버가 독립적으로 종료)하면 wait
호출이 리턴됩니다 (서버의 종료 코드 또는 신호가 수신 된 경우 신호 번호 + 128로 종료). 이후 쉘이 SIGTERM을 수신하면 _term
종료하기 전에 SIGTERM 트랩 핸들러로 지정된 함수 를 호출합니다 (여기서 정리를 수행하고을 사용하여 수동으로 신호를 서버 프로세스에 전파합니다 kill
).
wait
호출이 필요한지 잘 모르겠습니다 .
exec /bin/start/main/server --nodaemon
(이 경우 쉘 프로세스는 서버 프로세스로 대체하고 당신은 어떤 신호를 전파 할 필요가 없습니다) 또는 사용 /bin/start/main/server --nodaemon &
,하지만 exec
정말 의미가 없습니다.
_term()
기능 에서 wait "$child"
다시 해야 합니다. 다시 시작하기 전에 셸 스크립트가 종료되기를 기다리는 다른 감독 프로세스가 있거나 EXIT
정리를 수행하기 위해 트랩 되어 하위 프로세스가 완료된 후에 만 실행되도록해야하는 경우에 필요할 수 있습니다 .
Bash는 현재 대기중인 프로세스에 SIGTERM과 같은 신호를 전달하지 않습니다. 당신이하여 스크립트를 종료 할 경우 에 segueing 서버, 사용한다 (직접 서버를 시작한 것처럼 그것이 신호와 다른 작업을 처리 할 수 있도록) exec
할, 프로세스가 열릴와 쉘을 대체 :
#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon
당신이 어떤 이유로 주변의 껍질을 유지해야 할 경우의 조합을 사용한다 (예. 당신은 서버가 종료 한 후 몇 가지 정리를 할 필요) trap
, wait
및 kill
. SensorSmith의 답변을 참조하십시오 .
Andreas Veithen 은 (OP의 예와 같이) 호출에서 돌아올 필요가 없으면 exec
명령을 통한 호출만으로 충분하다고 지적합니다 ( @Stuart P. Bentley 's answer ). 그렇지 않으면 "전통적인" trap 'kill $CHILDPID' TERM
(@cuonglm의 답변)은 시작이지만 wait
트랩 처리기가 실행 된 후에 호출이 실제로 리턴되며 이는 자식 프로세스가 실제로 종료되기 전에 계속 될 수 있습니다. 따라서 "추가"호출 wait
이 권장됩니다 ( @ user1463361의 답변 ).
이것은 개선이지만 여전히 경쟁 조건을 가지므로 프로세스가 절대 종료되지 않을 수 있습니다 (신호기가 TERM 신호 전송을 재 시도하지 않는 한). 취약점은 트랩 핸들러를 등록하고 자식의 PID를 기록하는 것입니다.
다음은이 취약점을 제거합니다 (재사용을 위해 기능으로 패키지).
prep_term()
{
unset term_child_pid
unset term_kill_needed
trap 'handle_term' TERM INT
}
handle_term()
{
if [ "${term_child_pid}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
else
term_kill_needed="yes"
fi
}
wait_term()
{
term_child_pid=$!
if [ "${term_kill_needed}" ]; then
kill -TERM "${term_child_pid}" 2>/dev/null
fi
wait ${term_child_pid}
trap - TERM INT
wait ${term_child_pid}
}
# EXAMPLE USAGE
prep_term
/bin/something &
wait_term
대기 명령이 실제로 완료되기 전에 프로세스가 종료되었으므로 제공된 솔루션이 작동하지 않습니다. 그 기사 http://veithen.github.io/2014/11/16/sigterm-propagation.html 에서 마지막 스 니펫은 OpenShift에서 사용자 정의 sh 러너로 시작한 응용 프로그램의 경우 효과적입니다. Java 프로세스의 PID가 1 인 경우 불가능한 스레드 덤프를 얻을 수 있어야하므로 sh 스크립트가 필요합니다.
trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?