将 Paramiko 的标准输出用作带有子进程的标准输入

Use Paramiko's stdout as stdin with subprocess

如何在 Python 中的远程服务器上执行命令并将标准输出通过管道传输到本地命令?要在 Python 中完成 ssh host 'echo test' | cat,我已尝试

import paramiko
import subprocess

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('host', username='user')
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('echo test')
proc = subprocess.Popen(['cat'], stdin=ssh_stdout)
outs, errs = proc.communicate()
print(outs)

但我遇到异常 'ChannelFile' object has no attribute 'fileno'。 Paramiko 的 ssh_stdout 似乎不能用作 subprocess.Popen.

的标准输入

是的,subprocess 无法重定向 "fake" 文件的输出。它需要仅用 "real" 文件定义的 filenoio.BytesIO() 也没有)。

我会像下面的代码演示的那样手动完成:

proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE)
proc.stdin.write(ssh_stdout.read())
proc.stdin.close()

所以你告诉 Popen 输入是一个 管道 ,然后你在管道中写入 ssh 输出数据(并关闭它所以 cat知道什么时候必须结束)

根据文档,ChannelFile 对象没有直接包装实际的文件描述符(因为解密和解复用等发生在 SSH 中),所以它不能直接用作Popen.

的文件描述符

类似

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command('echo test')
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE)
while proc.poll() is not None:  # (fixed)
   buf = ssh_stdout.read(4096)
   if not buf:
       break
   proc.stdin.write(buf)

可能有用;即您手动读取 SSH stdout 流,一次最多 4096 个字节,并将它们写入子进程的 stdin 管道。 不过,我不确定当远程命令退出时上面的代码将如何运行,所以 YMMV。