Answers:
尝试:
#!/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
),使其进入Shell的作业控制系统。wait
然后,调用将等待具有指定PID的作业(服务器)完成,或等待任何信号被触发。
当shell收到SIGTERM
(或服务器独立退出)时,wait
调用将返回(以服务器的退出代码退出,或者在收到信号的情况下以信号编号+ 128退出)。之后,如果外壳程序接收到SIGTERM,它将_term
在退出之前调用指定为SIGTERM陷阱处理程序的函数(在该过程中,我们将进行任何清理,并使用手动将信号传播到服务器进程kill
)。
wait
需要调用吗?
exec /bin/start/main/server --nodaemon
(在这种情况下,将shell进程替换为服务器进程,并且不需要传播任何信号),要么使用/bin/start/main/server --nodaemon &
,但exec
实际上并没有意义。
_term()
您应该在函数中wait "$child"
再次终止。如果您还有其他监督过程在重新启动外壳脚本之前等待外壳脚本终止,或者您还被困EXIT
进行一些清理工作并且仅在子进程完成后才开始运行,则可能有必要。
Bash不会将诸如SIGTERM之类的信号转发到其当前正在等待的进程。如果您想通过进入服务器来结束脚本(允许它处理信号和其他任何事情,就像您直接启动了服务器一样),则应使用exec
,它将用正在打开的进程替换shell:
#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon
如果你需要保持周围的外壳因某种原因(即你需要做一些清理服务器终止后),你应该使用的组合trap
,wait
和kill
。请参阅SensorSmith的答案。
Andreas Veithen指出,如果您不需要从调用中返回(例如在OP的示例中),只需通过exec
命令进行调用就足够了(@Stuart P. Bentley的答案)。否则,“传统” 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,对于我的应用程序来说,最后一个代码片段在自定义sh运行程序的OpenShift中很好用。需要sh脚本是因为我需要具有获取线程转储的能力,而在Java进程的PID为1的情况下这是不可能的。
trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?