如何在Paramiko的.recv函数中接收完整大输出?
嘿,我来帮你搞定这个Paramiko.recv无法获取完整输出的问题~
解决Paramiko.recv无法获取完整输出的问题
首先得说清楚:直接调recv(nbytes)拿完整输出本来就不靠谱,因为它是按固定字节数读取的,完全不知道远程命令的输出什么时候结束——尤其是在交互式shell会话里,输出可能分批返回,还有提示符插在中间,单纯增大nbytes只是碰运气,根本解决不了本质问题。
下面给你两种针对Python2.7+Paramiko2.4.1的靠谱方案,根据你的场景选就行:
方案1:用exec_command(推荐,非交互式命令场景)
如果你的命令都是非交互式的(不需要输入密码、确认之类的操作),exec_command是最优解——它会自动等待命令执行完毕,然后你可以一次性读取所有stdout和stderr内容,完美避免截断问题。而且如果需要在同一会话里保持环境上下文,把多个命令用&&或;连起来就行。
示例代码:
#!/usr/bin/env python import paramiko user = raw_input("Enter your username please: ") upassw = raw_input("Enter your password please: ") # 要执行的命令列表,需要上下文的话可以合并成一个命令,比如"cd /tmp && ls -l" commands = ["ls -l", "echo $HOME", "cat /etc/os-release"] ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: # 连接远程主机 ssh.connect('your_host_ip', username=user, password=upassw) for cmd in commands: print("\n--- 执行命令: {} ---".format(cmd)) # 执行命令,获取三个流 stdin, stdout, stderr = ssh.exec_command(cmd) # 读取完整输出(stdout.read()会等到命令执行完再返回所有内容) output = stdout.read().decode('utf-8') error = stderr.read().decode('utf-8') if output: print("输出内容:\n{}".format(output)) if error: print("错误信息:\n{}".format(error)) finally: # 不管成功失败都关闭连接 ssh.close()
方案2:用invoke_shell+等待提示符(交互式/会话保持场景)
如果必须用交互式shell(比如需要执行sudo输入密码、或者要保持会话中的环境变量/工作目录),那得换个思路:通过**等待远程主机的提示符(比如$、#)**来判断命令输出是否结束,循环读取直到拿到完整内容。
示例代码:
#!/usr/bin/env python import paramiko import time user = raw_input("Enter your username please: ") upassw = raw_input("Enter your password please: ") # 定义一个读取输出直到提示符出现的函数 def read_until_prompt(channel, prompt, timeout=10): output = "" channel.settimeout(timeout) try: # 循环读取,直到输出里包含目标提示符 while prompt not in output: chunk = channel.recv(1024).decode('utf-8') if not chunk: # 没有更多数据,退出循环 break output += chunk # 可选:实时打印输出,方便调试 # print(chunk, end='') except paramiko.socket.timeout: print("\n警告:等待提示符超时") return output ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect('your_host_ip', username=user, password=upassw) # 创建交互式shell通道 channel = ssh.invoke_shell() time.sleep(1) # 等待初始登录输出加载完成 # 读取登录后的初始输出和提示符 initial_output = read_until_prompt(channel, "$ ") # 根据你的主机提示符修改,比如# 或者> print("初始登录输出:\n{}".format(initial_output)) commands = ["ls -l", "echo $HOME"] for cmd in commands: print("\n--- 发送命令: {} ---".format(cmd)) # 发送命令,记得加换行符 channel.send(cmd + "\n") time.sleep(0.5) # 给命令留执行时间,复杂命令可以延长 # 读取命令输出直到提示符出现 cmd_output = read_until_prompt(channel, "$ ") # 清理输出:去掉命令本身和最后的提示符 cleaned_output = cmd_output.replace(cmd + "\n", "").rstrip("$ ") print("命令输出:\n{}".format(cleaned_output)) finally: ssh.close()
注意点:
- 提示符要和远程主机的实际提示符匹配,比如root用户是
#,普通用户可能是$或者自定义的提示符; time.sleep()的时间可以根据命令复杂度调整,也可以用更智能的方式(比如检查输出中是否有命令执行的特征)代替固定sleep;- 如果遇到中文输出乱码,把
decode('utf-8')换成目标系统的编码,比如gbk。
内容的提问来源于stack exchange,提问作者ME_sociaty
相关产品推荐
相关产品推荐

