Lor*_*enz 120 shell bash signals docker
我有一个 Bash 脚本,它看起来类似于:
#!/bin/bash
echo "Doing some initial work....";
/bin/start/main/server --nodaemon
Run Code Online (Sandbox Code Playgroud)
现在,如果运行脚本的 bash shell 收到一个 SIGTERM 信号,它也应该向正在运行的服务器发送一个 SIGTERM(它会阻塞,所以不可能有陷阱)。那可能吗?
cuo*_*glm 139
尝试:
#!/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"
Run Code Online (Sandbox Code Playgroud)
通常,bash在子进程执行时会忽略任何信号。启动服务器&将使其后台进入 shell 的作业控制系统,并$!保存服务器的 PID(与wait和一起使用kill)。wait然后调用将等待具有指定 PID(服务器)的作业完成,或等待任何信号被触发。
当 shell 接收到SIGTERM(或服务器独立退出)时,wait调用将返回(以服务器的退出代码退出,或者在接收到信号时以信号号 + 128 退出)。之后,如果 shell 接收到 SIGTERM,它将_term在退出之前调用指定为 SIGTERM 陷阱处理程序的函数(我们执行任何清理工作并使用 手动将信号传播到服务器进程kill)。
Stu*_*ley 103
Bash 不会将 SIGTERM 之类的信号转发给它当前正在等待的进程。如果你想通过进入你的服务器来结束你的脚本(允许它处理信号和其他任何东西,就像你直接启动了服务器一样),你应该使用exec,它将用正在打开的进程替换外壳:
#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon
Run Code Online (Sandbox Code Playgroud)
如果你需要保持周围的外壳因某种原因(即您所需要的服务器终止后做一些清理),你应该使用的组合trap,wait和kill。请参阅SensorSmith 的回答。
Sen*_*ith 40
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} 2>/dev/null
trap - TERM INT
wait ${term_child_pid} 2>/dev/null
}
# EXAMPLE USAGE
prep_term
/bin/something &
wait_term
Run Code Online (Sandbox Code Playgroud)
小智 7
提供的解决方案对我不起作用,因为在等待命令实际完成之前进程已被终止。我发现文章http://veithen.github.io/2014/11/16/sigterm-propagation.html,最后一个片段在我的应用程序中运行良好,在 OpenShift 中使用自定义 sh runner 启动。需要 sh 脚本,因为我需要能够获取线程转储,这在 Java 进程的 PID 为 1 的情况下是不可能的。
trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
95042 次 |
| 最近记录: |