Python subprocess.Popen调用SSH时kill提前执行等异常如何解决
问题核心原因
- 代码为同步顺序执行,
proc.kill()会在写入命令、关闭stdin后立刻触发,不会等待SSH远端执行完opkg更新操作,多数时候命令还没传到远端启动,本地SSH进程就被强制终止,连接直接断开。 - 代码没有做SSH进程存活校验,一旦SSH因为认证失败、网络不通、host key校验拦截等原因提前退出,stdin管道已经关闭,后续调用write就会触发管道断开错误。
- 第二条命令末尾缺少换行符,SSH交互shell无法识别到命令输入完成,会卡在等待输入的状态,不会执行该命令。
修复方法
不要在发送完命令后立刻调用kill(),关闭stdin后SSH会感知到输入流结束,自动等待所有已下发命令执行完成后退出,只需要调用wait()等待进程自然结束即可,仅在超时、异常场景下才需要主动kill进程回收资源。
修复后的可运行代码:
import subprocess # 定义待执行命令,所有命令末尾补全换行符 cmds = [ "opkg update\n", "echo process 2\n" ] # SSH连接参数增加常用配置,避免host key提示、连接无超时等问题 ssh_args = [ "ssh", "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=10", "root@192.168.1.1" ] proc = subprocess.Popen( ssh_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) try: for cmd in cmds: # 写入命令前先检查进程是否已异常退出 if proc.poll() is not None: raise RuntimeError(f"SSH进程提前终止,退出码:{proc.returncode}") proc.stdin.write(cmd.encode()) proc.stdin.flush() proc.stdin.close() # 等待命令执行完成,设置5分钟超时避免无限挂起 stdout, stderr = proc.communicate(timeout=300) print("执行标准输出:\n", stdout.decode(errors="ignore")) if proc.returncode != 0: print("执行错误输出:\n", stderr.decode(errors="ignore")) except subprocess.TimeoutExpired: proc.kill() proc.communicate() print("命令执行超时,已强制终止进程") except BrokenPipeError: proc.kill() print("SSH连接异常断开,写入管道失败") finally: # 兜底回收进程资源,避免僵尸进程 if proc.poll() is None: proc.kill() proc.wait()
排查要点
- 先手动在本地终端执行
ssh root@192.168.1.1,确认已配置免密登录,能正常进入路由器shell,避免密码交互、host key校验导致SSH进程直接退出。 - 调试阶段可以先把
opkg update替换为echo test这类短耗时命令,验证流程跑通后再替换为更新命令。 - 必须接管stdout、stderr输出,否则远端命令输出堆满系统管道缓冲区后,会导致SSH进程卡死无法退出。
内容的提问来源于stack exchange,提问作者gubwan
相关产品推荐
相关产品推荐

