使用Paramiko执行命令后channel.recv未返回提示符,循环无法终止
问题分析与修复方案
核心问题点
- 错误判断
channel.recv:channel.recv是方法而非属性,if channel.recv:始终为真,无法正确识别数据是否就绪。 - 重复调用
recv导致数据丢失:连续两次调用channel.recv(1024)会读取不同的缓冲区数据,可能使COMMAND_COMPLETED被读取后未被检测到。 - 固定
time.sleep不可靠:依赖固定等待时间应对命令执行延迟,易因网络或服务器性能波动导致逻辑失效。
修正后的代码
import paramiko import time import socket def list_pass(hostname, user): # 替换为实际的密码获取逻辑 return "your_password_here" hostname = "your_server_hostname" ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(hostname, username='xyz', password=list_pass(hostname, 'xyz')) command = 'puppet agent -t --no-use_cached_catalog ; echo COMMAND_COMPLETED' channel = ssh.invoke_shell() # 等待初始提示符就绪 while not channel.recv_ready(): time.sleep(0.1) channel.send("su -\n") # 等待密码输入提示 while True: if channel.recv_ready(): output = channel.recv(1024).decode() if "Password:" in output: break time.sleep(0.1) channel.send(list_pass(hostname, 'root') + "\n") # 等待切换root后的提示符(根据实际服务器提示符调整,比如#号) while True: if channel.recv_ready(): output = channel.recv(1024).decode() if "#" in output: break time.sleep(0.1) channel.send(command + '\n') # 循环读取输出直到找到结束标记 full_output = "" while True: if channel.recv_ready(): chunk = channel.recv(1024).decode() full_output += chunk print(chunk, end='') if "COMMAND_COMPLETED" in full_output: break time.sleep(0.1) channel.close() ssh.close() except paramiko.AuthenticationException: print("Authentication failed") except socket.gaierror: print(f"Can't connect to {hostname}. Verify if server exists and it's up.")
关键优化说明
- 用
recv_ready()判断数据就绪:替代固定sleep,高效准确地检测缓冲区是否有数据。 - 统一收集输出内容:将所有读取到的内容存入
full_output,避免多次recv导致数据遗漏,确保结束标记能被正确检测。 - 基于提示符的流程控制:通过检测
Password:和root提示符来判断步骤完成,比固定sleep更可靠。
内容的提问来源于stack exchange,提问作者Pranit Dhumne
相关产品推荐
相关产品推荐

