如何检测通过Paramiko执行sudo命令时是否需输入密码?
解决Paramiko执行sudo命令时的密码检测与缓冲区卡顿问题
一、检测是否需要输入sudo密码
执行sudo命令时,需要密码的场景下,sudo通常会向stderr输出类似[sudo] password for username:的提示。可以通过监听stderr输出结合超时判断来检测:
- 用
select模块监听stderr的可读状态,设置合理超时(比如3秒),避免无限等待。 - 若stderr有输出,读取内容并检查是否包含sudo密码请求的关键词(如
[sudo] password for)。
代码示例:
import paramiko import select # 建立SSH连接 client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect("虚拟机IP", username="登录账号", password="登录密码") # 执行sudo修改root密码命令 stdin, stdout, stderr = client.exec_command("sudo passwd root") need_sudo_pass = False # 监听stderr,判断是否需要输入sudo密码 read_ready, _, _ = select.select([stderr], [], [], 3) if read_ready: err_output = stderr.read().decode("utf-8") if "[sudo] password for" in err_output: need_sudo_pass = True # 需要输入sudo密码的场景 if need_sudo_pass: stdin.write("你的sudo密码\n") stdin.flush() # 必须调用flush,确保内容发送到远程主机
二、解决stdout/stderr卡顿问题
直接打印stdout时卡顿,是因为远程进程输出缓冲区被占满后会阻塞,导致本地程序无法继续读取。解决方法是用select同时监听stdout和stderr,采用非阻塞逐行读取:
# 处理passwd命令的后续交互(输入新root密码两次) stdin.write("新root密码\n") stdin.flush() stdin.write("新root密码\n") stdin.flush() # 循环读取输出,避免缓冲区阻塞 while True: # 监听stdout和stderr,超时1秒 read_ready, _, _ = select.select([stdout, stderr], [], [], 1) if stdout in read_ready: line = stdout.readline() if not line: # 读取到EOF,结束循环 break print(f"标准输出: {line.strip()}") if stderr in read_ready: line = stderr.readline() if not line: break print(f"错误输出: {line.strip()}") # 关闭连接 client.close()
关于stdin的使用说明
Paramiko的stdin是类文件对象,没有专门的"输入方法",直接用write()写入内容后,必须调用flush()强制发送缓冲区内容到远程主机,否则内容可能滞留在本地缓冲,导致远程进程无法接收输入。
内容的提问来源于stack exchange,提问作者SHAO CHUN CHENG
相关产品推荐
相关产品推荐

