Python使用subprocess调用SSH时伪终端分配及多命令执行问题
1. subprocess.run配置SSH伪终端的参数
报错Pseudo-terminal will not be allocated because stdin is not a terminal是因为SSH默认仅在本地标准输入为终端设备时分配伪终端,非交互场景下需要给SSH命令添加-tt参数强制分配伪终端。subprocess.run的完整配置示例如下:
import subprocess cmd = ["ssh", "-tt", "-i", "sshkey.pem", "user@111.1.1.1"] # 单次执行exit命令 result = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input="exit\n", text=True ) print(result.stdout)
2. 流式执行多条命令的实现
subprocess.run和Popen.communicate都仅支持单次输入输出,调用后会直接关闭管道,不满足多命令交互的需求。你需要直接操作Popen实例的标准输入、标准输出文件对象实现流式交互,注意需配合行缓冲、手动清空缓冲区操作,避免命令/输出滞留:
import subprocess cmd = ["ssh", "-tt", "-i", "sshkey.pem", "user@111.1.1.1"] p = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1 # 开启行缓冲 ) # 定义读取命令输出的工具函数,可根据自身终端提示符调整终止条件 def read_output(): output = [] while True: line = p.stdout.readline() # 替换为你的SSH终端的提示符特征,比如root@xxx:~# 之类的内容 if "user@111.1.1.1" in line: break if line: output.append(line.strip()) return "\n".join(output) # 执行第一条命令 p.stdin.write("ls -la\n") p.stdin.flush() print("ls命令输出:\n", read_output()) # 执行第二条命令 p.stdin.write("cd /opt && mkdir test\n") p.stdin.flush() print("创建目录命令执行完成") # 执行第三条命令 p.stdin.write("pwd\n") p.stdin.flush() print("pwd命令输出:\n", read_output()) # 退出SSH会话 p.stdin.write("exit\n") p.stdin.flush() p.wait()
补充说明
如果存在复杂交互场景(比如sudo密码输入、特殊字符转义、长时间会话保活等),更推荐直接使用SSH协议库实现,不需要额外处理子进程管道的缓冲区、阻塞等问题,开发成本更低。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

