如何安全异步中断经SSH+BASH启动的Python无限循环脚本?
环境说明
我需要在远程主机运行Python脚本,执行流程为:本地BASH脚本 --> SSH --> 远程BASH脚本 --> 远程Python脚本。该Python脚本负责配置连接远程服务器的DAQ设备,执行采样与信号生成的while(True)无限循环。本地开发时,我通过Ctrl+C触发KeyboardInterrupt异常中断循环,并安全关闭设备会话;退出Python脚本后,远程BASH脚本还会执行后续清理操作。
脚本示例:
local-script.sh:
ssh user@remotehost "remote-script.sh"
remote-script.sh:
python3 infinite-loop.py
infinite-loop.py:
while True: # 执行采样/信号生成操作...
问题描述
迁移到远程通过SSH运行后,无法用Ctrl+C安全退出Python脚本。按下快捷键后,DAQ设备仍在运行,远程服务器上的Python与BASH脚本进程残留,必须手动杀死才能避免再次运行时出现重复实例。实际仅关闭了SSH会话,远程进程状态如下:
Remote Python Script = 仍在运行 Remote BASH Script = 仍在运行 Remote SSH Session = 已关闭 Local BASH Script = 活跃状态(按下Ctrl+C后回到这里)
需求与尝试
我希望能异步中断(而非完全退出)经SSH+BASH启动的Python脚本,最好适配现有BASH --> SSH --> BASH --> Python框架,且尽量少安装额外pip依赖。
编辑1:根据建议尝试BASH的trap语句但未成功,监控进程发现,按下Ctrl+C后回到本地BASH脚本,远程服务器上的BASH和Python进程仍在运行,仅SSH会话被终止。
解决方案
1. 给SSH命令添加-t参数传递终端信号
默认SSH不会将本地的SIGINT信号(Ctrl+C触发)传递给远程命令,添加-t参数可强制分配伪终端,让信号能穿透到远程进程链。
修改local-script.sh:
ssh -t user@remotehost "remote-script.sh"
2. 远程BASH脚本添加信号捕获与进程清理逻辑
在remote-script.sh中用trap捕获SIGINT,确保能终止Python进程并执行后续操作:
#!/bin/bash # 定义中断处理函数 cleanup() { echo "触发中断,开始清理..." # 终止当前BASH进程下的Python子进程 pkill -P $$ python3 # 此处可添加DAQ设备的额外关闭命令 echo "清理完成" } # 绑定SIGINT信号到cleanup函数 trap cleanup SIGINT # 启动Python脚本 python3 infinite-loop.py # Python正常退出后也执行清理(可选) cleanup
3. Python脚本显式处理中断信号
在Python脚本中注册信号处理函数,确保收到SIGINT时安全关闭设备:
import signal import sys def handle_interrupt(sig, frame): print("收到中断信号,安全关闭DAQ设备...") # 此处添加关闭设备会话的代码 sys.exit(0) # 注册SIGINT信号处理 signal.signal(signal.SIGINT, handle_interrupt) while True: # 执行采样/信号生成操作 pass
验证效果
修改后按下Ctrl+C:
- 本地SSH会话将SIGINT传递给远程BASH脚本
- 远程BASH触发清理函数,终止Python进程
- Python执行设备关闭逻辑后退出
- 远程BASH完成后续操作后终止,无残留进程
内容的提问来源于stack exchange,提问作者SchtungDung

