Python paramiko脚本,在exec_命令()期间读取输出时出现问题

Python paramiko脚本,在exec_命令()期间读取输出时出现问题,python,ssh,paramiko,Python,Ssh,Paramiko,背景: 我正在使用python和paramiko来自动化每次我必须为一个类提交一个程序的过程。我们使用一个名为“handin”的命令来提交源代码,但这必须在学校的计算机上完成。因此,当我从家里提交代码时,我必须:将sftp放入学校服务器,将文件放入目录,将ssh放入学校计算机,使用“handin”命令 我可以成功地把文件放到学校的机器上。当我尝试使用exec_命令(“handinmyfiles”)然后读取输出以确定下一个操作时,就会出现问题 所以我有 try: (stdin, stdout

背景: 我正在使用python和paramiko来自动化每次我必须为一个类提交一个程序的过程。我们使用一个名为“handin”的命令来提交源代码,但这必须在学校的计算机上完成。因此,当我从家里提交代码时,我必须:将sftp放入学校服务器,将文件放入目录,将ssh放入学校计算机,使用“handin”命令

我可以成功地把文件放到学校的机器上。当我尝试使用exec_命令(“handinmyfiles”)然后读取输出以确定下一个操作时,就会出现问题

所以我有

try:
   (stdin, stdout, stderr) = client.exec_command(s)
except:
   print 'whoops'
   sys.exit()
print stdout.readlines()
但由于某种原因,这会导致死锁,脚本似乎什么也没做,我最终不得不终止整个过程(ctrl+c不起作用)。我不确定exec_命令是否没有正确完成(即使它正在退出try/catch块),或者我是否有网络问题或其他问题

有什么想法吗

更新:

问题在于在执行过程中与handin命令交互。执行命令后,handin可能仍在运行,也可能尚未运行。如果它是第一次提交,它会说成功,等等,然后完成执行。一切都很好。但是如果我重新提交,我必须为每个文件授权覆盖(stdin.write('y'))

TL/DR:


如何检查exec_command()是否仍在运行,是否在等待输入,以及是否在相应地从stdout读取行()。

问题可能是远程命令正在等待输入(它希望您向stdin写入一些内容,除非您这样说,否则不知道您不会这样做)。试试
stdin.channel.shutdown\u write()
(我相信
stdin.close()
本身不会起作用:那只会导致刷新)

我看不出上面的代码有什么问题。下面的程序是一个完整的脚本,它登录到主机并运行ls命令以查看文件。我刚试过,它对我有效。也许试试这个,看看它是否适合你。如果它不工作,我怀疑您的ssh服务器、正在运行的命令或paramiko安装可能会出现一些特定的问题。如果它确实适合您,那么只需对其进行更改,以实现您现有的功能,并查看它在哪里中断

import paramiko
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('<ip address here>',username='<username here>',password='<password here>')
stdin,stdout,stderr = ssh.exec_command("ls /")
print stdout.readlines()
导入paramiko
ssh=paramiko.SSHClient()
ssh.set_缺少_主机_密钥_策略(paramiko.AutoAddPolicy())
ssh.connect(“”,用户名=“”,密码=“”)
stdin,stdout,stderr=ssh.exec_命令(“ls/”)
打印stdout.readlines()

如果这对您有效,我的下一个建议是尝试将“ls/”替换为您尝试运行的实际handin命令。可能是命令挂起等待用户输入等。

要解决此问题并获取Ifconfig的输出,您可能需要尝试使用选项get_pty=True

e、 g:


这是一个旧的线程,但我也看到了这个问题。这是因为Paramiko中有一个bug,它无法处理远程命令中的大型STDOUT,因此挂起

参考:


可能的解决方案:

好的,所以我最近也遇到了这个问题。检查文档和更多的搜索让我找到一个可接受的答案,我可以使用它发送输入并检查可能需要用户输入的简单脚本的输出

而不是尝试使用等待程序完成运行的
.read()
.readline()
。 查询它们,只需要一个字节,比如
.read(1)
.readline(1)
,直到
stdout.channel.recv_ready()
返回
True
,它表示在 阅读标准 最好使用
stdout.channel.recv(9999)
而不是
realine(1)
,因为它允许您请求9999个字节,而不是读取/读取行中的1个字节,并且如果请求的字节数超过现有字节数,您不会陷入死锁

下面是查看执行基本sudo命令的样板代码

ssh.connect(
主机名=主机,
端口=端口,
用户名=用户名,
密码=密码,
)
def读线(标准输出):
行=“”
而sout.channel.recv_ready():
行+=源读取行(1)
回程线
>>stdin,stdout,stderr=ssh.exec_命令('sudo ls-al/root',get_pty=True)
>>输出=读线(标准输出)
>>打印(输出)
“[sudo]用户密码:”
>>如果输出中有“[sudo]密码用于”:
stdin.write(密码+“\n”)
stdin.flush()
>>输出=读线(标准输出)
>>打印(输出)
总数88
drwx------7根根根14五月6日21:40。
drwxr-xr-x 18根目录24 Apr 29 18:46。。
-rw-----1根根3619五月7日13:19.巴什胡历史

现在,您可以使用它基本上缩放到您想要的任何检查。使用invoke_shell可能有更好的方法来实现这一点,但这符合我的目的。

这正是我需要执行readline检查的内容。如果您多次提交,它会询问您是否要为每个文件覆盖[y/N],如果这是第一次不需要进一步输入。如何在exec_命令期间检查输出?stdout.readlines()实际上是读取ssh命令的输出,而不是从脚本“读取”输入并将其发送到ssh命令。要做到这一点,您需要stdin.write()。我知道这一点,但您误解了。我更新了我原来的帖子,也许这会澄清一些事情up@macgregor你找到解决问题的办法了吗?我正在寻找你在这里需要的东西。是的,我连接良好,基本命令工作得很好。我试图使用readline来确定在命令执行过程中下一步要输入什么,这几乎可以肯定是您的handin命令。它需要互动行为。看看这个例子,它在链接中使用了'sudodmesg',因此必须响应密码提示:好的,我需要动态地执行这个操作。有没有一种方法可以在命令执行期间读取stdout来检查我需要写多少次“y”而不是“o”
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def MonitorProcess():
    ssh.connect('10.2.0.230', username='ibmsys1', password='passw0rd', timeout=5)
    stdin, stdout, stderr = ssh.exec_command('/sbin/ifconfig', timeout=3, get_pty=True)
    #stdin, stdout, stderr = ssh.exec_command('/sbin/ifconfig') -> simple exec ex.
    print stdout.read()

MonitorProcess()