Python subprocess.Popen管道意外阻塞IO

时间:2018-04-24 21:32:05

标签: python linux python-3.x ssh pty

我正在尝试使用subprocess.Popen来控制ssh进程并通过管道与它进行交互,如下所示:

p=subprocess.Popen(['ssh','-tt','LOGIN@HOSTNAME'], stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                    universal_newlines=True)

while True:
    (out_stdout,out_stderr)=p.communicate(timeout=10)
    if out_stderr:
        print(out_stderr)
    if not out_stdout:
        raise EOFError
    print(out_stdout)

没有ssh的'-tt'选项,这样可以正常工作。但是,如果没有分配伪tty,我需要在ssh的远程端进行交互的程序中断,所以我不得不使用它。

这似乎做的是p.communicate读取然后无限期地阻塞(或直到超时),即使输入可用。

我已经使用对io.read,select.select等的较低级别调用重写了这一点,以避免通过Popen.communicate。 Select实际上会将文件描述符返回为就绪,但对该文件描述符的后续io.read也将被阻止。如果我禁用'通用换行符'并在Popen调用中设置'bufsize = 0'它然后工作正常,但后来我被迫做自己的二进制/ unicode转换和行结束处理。

值得一提的是,禁用p.communicate版本中的universal_newlines也会无限期地阻止,所以不仅如此。

关于如何在不必重新实现所有内容的情况下使线路缓冲输入正常工作的任何建议?

1 个答案:

答案 0 :(得分:0)

有子库的替代方法和SSH二进制文件更适合此类任务。

parallel-ssh

from pssh.pssh2_client import ParalellSSHClient
client = ParallelSSHClient(['HOSTNAME'], user='LOGIN')
output = client.run_command('echo', use_pty=True)

for host, host_output in output.items():
    for line in host_output.stdout:
        print(line)

echo替换为您需要运行的命令,或者如果不需要命令则保持原样。即使远程端自动执行某些操作,库也要求将某些内容作为命令传入。

另请参阅同一项目的single host SSHClient文档。

每个文档,行解析和编码都由跨平台的库处理。

还有其他像paramiko和ssh2-python这些更低级别,并且需要更多相同代码 - 请参阅各自的主页以获取示例。