从 Paramiko 命令捕获标准输出 [英] Capturing standard out from a Paramiko command

查看:69
本文介绍了从 Paramiko 命令捕获标准输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Paramiko 的 SSHClient.exec_command() 有一个包装器.我想捕捉标准输出.这是我的函数的简化版本:

I have a wrapper around Paramiko's SSHClient.exec_command(). I'd like to capture standard out. Here's a shortened version of my function:

def __execute(self, args, sudo=False, capture_stdout=True, plumb_stderr=True,
  ignore_returncode=False):

  argstr = ' '.join(pipes.quote(arg) for arg in args)

  channel = ssh.get_transport().open_session()
  channel.exec_command(argstr)

  channel.shutdown_write()

  # Handle stdout and stderr until the command terminates
  captured = []

  def do_capture():
    while channel.recv_ready():
      o = channel.recv(1024)
      if capture_stdout:
        captured.append(o)
      else:
        sys.stdout.write(o)
        sys.stdout.flush()

    while plumb_stderr and channel.recv_stderr_ready():
      sys.stderr.write(channel.recv_stderr(1024))
      sys.stderr.flush()

  while not channel.exit_status_ready():
    do_capture()

  # We get data after the exit status is available, why?
  for i in xrange(100):
    do_capture()

  rc = channel.recv_exit_status()
  if not ignore_returncode and rc != 0:
    raise Exception('Got return code %d executing %s' % (rc, args))

  if capture_stdout:
    return ''.join(captured)

paramiko.SSHClient.execute = __execute

do_capture() 中,每当 channel.recv_ready() 告诉我可以从命令的标准输出接收数据时,我调用 channel.recv(1024) 并将数据附加到我的缓冲区.当命令的退出状态可用时,我停止.

In do_capture(), whenever channel.recv_ready() tells me that I can receive data from the command's stdout, I call channel.recv(1024) and append the data to my buffer. I stop when the command's exit status is available.

但是,似乎在退出状态之后的某个时间点会出现更多标准输出数据.

However, it seems like more stdout data comes at some point after the exit status.

# We get data after the exit status is available, why?
for i in xrange(100):
  do_capture()

我不能只调用一次 do_capture(),因为看起来 channel.recv_ready() 会返回 False 几毫秒,然后返回 True,然后接收到更多数据,然后再次 False.

I can't just call do_capture() once, as it seems like channel.recv_ready() will return False for a few milliseconds, and then True, and more data is received, and then False again.

我使用 Python 2.7.6 和 Paramiko 1.15.2.

I'm using Python 2.7.6 with Paramiko 1.15.2.

推荐答案

我遇到了同样的问题.问题是在命令退出后,stout 或 stderr 缓冲区中可能仍有数据,仍在通过网络传输或其他任何内容.我通读了 paramiko 的源代码,显然一旦 chan.recv() 返回空字符串,所有数据都已被读取.

I encountered the same problem. The problem is that after the command exited there may still be data on the stout or stderr buffers, still on its way over the network, or whatever else. I read through paramiko's source code and apparently all data's been read once chan.recv() returns empty string.

所以这是我试图解决它,直到现在它一直在工作.

So this is my attempt to solve it, until now it's been working.

def run_cmd(ssh, cmd, stdin=None, timeout=-1, recv_win_size=1024):
    '''
    Run command on server, optionally sending data to its stdin

    Arguments:
        ssh           -- An instance of paramiko.SSHClient connected
                         to the server the commands are to be executed on
        cmd           -- The command to run on the remote server
        stdin         -- String to write to command's standard input
        timeout       -- Timeout for command completion in seconds.
                         Set to None to make the execution blocking.
        recv_win_size -- Size of chunks the output is read in

    Returns:
        A tuple containing (exit_status, stdout, stderr)
    '''

    with closing(ssh.get_transport().open_session()) as chan:
        chan.settimeout(timeout)
        chan.exec_command(cmd)
        if stdin:
            chan.sendall(stdin)
            chan.shutdown_write()

        stdout, stderr = [], []

        # Until the command exits, read from its stdout and stderr
        while not chan.exit_status_ready():
            if chan.recv_ready():
                stdout.append(chan.recv(recv_win_size))
            if chan.recv_stderr_ready():
                stderr.append(chan.recv_stderr(recv_win_size))

        # Command has finished, read exit status
        exit_status = chan.recv_exit_status()

        # Ensure we gobble up all remaining data
        while True:
            try:
                sout_recvd = chan.recv(recv_win_size)
                if not sout_recvd and not chan.recv_ready():
                    break
                else:
                    stdout.append(sout_recvd)
            except socket.timeout:
                continue

        while True:
            try:
                serr_recvd = chan.recv_stderr(recv_win_size)
                if not serr_recvd and not chan.recv_stderr_ready():
                    break
                else:
                    stderr.append(serr_recvd)
            except socket.timeout:
                continue

    stdout = ''.join(stdout)
    stderr = ''.join(stderr)

    return (exit_status, stdout, stderr)

这篇关于从 Paramiko 命令捕获标准输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆