Shell 脚本如何传递 SIGTERM 信号给子程序

假如你写了个 shell 脚本,来运行目标程序,比如 java,然后再用 supervisor 来配置启动这个 shell 脚本。

cat start.sh

#!/bin/bash

# Prepare the JVM command line
...

$JAVA_EXECUTABLE $JAVA_ARGS

# Clean up
...

cat supervisor.conf

[program:testjava]
command=/home/kyle/testjava/start.sh
directory = /home/kyle/testjava
autorestart=true
user=ubuntu
redirect_stderr = true
stdout_logfile = /var/log/supervisor/testjava.log

这时候会有个问题,当 supervisor stop 你的程序的时候,shell 脚本退出了,然后程序却还在。

这是因为 TERM 信号被 shell 进程接收到了,但是 shell 并没有把信号转给子进程。

有个简单的解决办法,就是在程序运行命令前面,加上 exec,这样程序进程会替换当前的 bash shell 进程。

#!/bin/bash
...
exec $JAVA_EXECUTABLE $JAVA_ARGS

但是这个方案有个问题,如果想在 shell 脚本中,捕捉到程序退出,然后做一些事情,就没有办法了。

这时候可以使用 wait,以及 trap 命令来实现,具体可以搜索下这两个命令的文档。

#!/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"

#!/bin/bash
...
trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?
...

参考资料: