paramiko 合并 stdout 和 stderr

13 投票
3 回答
20939 浏览
提问于 2025-04-16 04:45

我正在尝试把标准输出和标准错误的结果合并在一起。我认为可以通过一个叫做set_combine_stderr()的Channel对象来实现。

这是我正在做的事情:

SSH = paramiko.SSHClient()
#I connect and everything OK, then:
chan = ssh.invoke_shell()
chan.set_combine_stderr(True)
chan.exec_command('python2.6 subir.py')
resultado = chan.makefile('rb', -1.)

但是,当我尝试保存结果时(上面最后一行,chan.makefile()),我遇到了以下错误:

错误:通道已关闭。

任何帮助都将非常感谢。

3 个回答

3

@AaronMcSmooth: 我指的是我通过SSH连接的电脑上的标准输出和错误输出。

我最后做了这个:

stdin, stdout, stderr = ssh.exec_command(...)

output = stdin.read().strip() + stdout.read().strip()

对于我的应用来说,区分标准输出和错误输出并不重要,但我觉得把它们合在一起的方式不是最好的。

SSHClient.exec_command()的代码是(查看paramiko的源代码):

def exec_command(self, command, bufsize=-1):
    chan = self._transport.open_session() 
    chan.exec_command(command) 
    stdin = chan.makefile('wb', bufsize) 
    stdout = chan.makefile('rb', bufsize) 
    stderr = chan.makefile_stderr('rb', bufsize) 
    return stdin, stdout, stderr

我在这个通道上执行相同的操作,但收到了“通道已关闭”的错误。

6

好的,我知道这个话题有点老了,但我遇到了同样的问题,找到了一种(可能不太)好看的解决办法。你只需要在远程服务器上运行命令,把错误信息(stderr)重定向到标准输出(stdout),然后始终从标准输出读取信息。比如:

client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('hostname', username='user', password='pass')

stdin,stdout,stderr = client.exec_command('python your_script.py 2> \&1')
print stdout.read()
22

虽然说 set_combine_stderr 可以把 stderr(错误信息)转到 stdout(正常输出)流里,但它的顺序是乱七八糟的,所以你得到的结果可能不是你想要的。你可能希望看到的,是按写入顺序排列的行,就像在本地终端窗口运行命令一样。相反,应该使用 get_pty。这样做会让服务器通过一个伪终端来运行这些行,保持它们的时间顺序。

这里有一个测试程序,叫 outerr.py,它会在 stdoutstdin 上交替写入行。假设它位于 llmps@meerkat2 的主目录下。

#!/usr/bin/env python

import sys

for x in xrange(1, 101):
    (sys.stdout, sys.stderr)[x%2].write('This is line #%s, on std%s.\n' %
                (x, ('out', 'err')[x%2]))

现在试试下面的代码来远程运行它:

#!/usr/bin/env python

import paramiko

def connect():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect('meerkat2', username='llmps', password='..')
    return ssh

def runTest(ssh):
    tran = ssh.get_transport()
    chan = tran.open_session()
    # chan.set_combine_stderr(True)
    chan.get_pty()
    f = chan.makefile()
    chan.exec_command('./outerr.py')
    print f.read(),

if __name__ == '__main__':
    ssh = connect()
    runTest(ssh)
    ssh.close()

如果你运行上面的代码,你应该能看到按写入顺序排列的100行。如果你把 chan.get_pty() 这一行注释掉,改为取消注释 chan.set_combine_stderr(True),那么你会发现每次运行时 stdoutstderr 的行会随机混在一起。

撰写回答