You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何终止由后台运行的Bash脚本启动的ROS2节点?

解决ROS2脚本后台启动后无法终止所有节点的问题

这个问题我之前在部署多组ROS2节点时也碰到过,核心原因是你保存的PID只是bash脚本本身的进程ID,但ROS2节点(不管是用ros2 run还是launch启动的)都是脚本的子进程。默认情况下,kill -TERM只会终止脚本进程,不会自动把信号传递给它的子进程,导致节点还在后台运行。下面给你几个可靠的解决方案:

方法1:使用进程组(Process Group)批量终止

所有由脚本启动的进程默认会属于同一个进程组,进程组ID(PGID)就是脚本的PID。我们可以通过终止整个进程组来一次性杀掉所有相关节点:

启动命令(修改后)

./${SCRIPTFILE} > $LOGFILE & 
# 获取脚本的进程组ID(和脚本PID一致)
PGID=$(ps -o pgid= $! | grep -o '[0-9]*')
echo $PGID > $PIDFILE

停止命令(修改后)

# 负号表示终止整个进程组,而非单个进程
kill -TERM -$(cat $PIDFILE) 2>/dev/null
# 清理PID文件(可选)
rm -f $PIDFILE

这个方法最直接,能确保所有由该脚本启动的子进程(包括嵌套的ROS2节点进程)都被终止。

方法2:在脚本内部添加信号捕获,主动清理子进程

修改你的ROS2启动脚本,让它在收到终止信号时,主动杀掉所有自己启动的子进程。在脚本的开头添加以下代码:

# 当脚本收到EXIT/TERM/INT信号时,终止自己的进程组(所有子进程)
trap 'kill -- -$$' EXIT TERM INT

$$代表脚本自身的PID,kill -- -$$就是终止整个进程组。这样你原来的启动和停止命令不需要修改:

  • 启动:./${SCRIPTFILE} > $LOGFILE & echo $! > $PIDFILE
  • 停止:kill -TERM $(cat $PIDFILE) 2>/dev/null

当你kill脚本PID时,脚本会触发trap语句,自动清理所有子节点进程。

方法3:通过父PID筛选并终止子进程

如果上面的方法不适用,你可以通过pgrep找到所有父PID为脚本PID的进程,逐一终止:

停止命令

# 先杀掉所有子进程
kill -TERM $(pgrep -P $(cat $PIDFILE)) 2>/dev/null
# 再杀掉脚本本身
kill -TERM $(cat $PIDFILE) 2>/dev/null
rm -f $PIDFILE

不过这个方法可能存在遗漏(比如ROS2节点又启动了更深层的子进程),不如前两种方法可靠,只推荐作为备选。


内容的提问来源于stack exchange,提问作者Marvin-wtt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:45:47