2010-09-29 18 views
9

Estoy tratando de combinar la salida de stdout y stderr. Mi creencia es que esto se puede hacer con set_combine_stderr() de un objeto Channel.paramiko combinar stdout y stderr

Esto es lo que estoy haciendo:

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.) 

Sin embargo, me sale el siguiente error al intentar almacenar el resultado (la última línea anterior, chan.makefile()):

Error: Channel closed.

Cualquier ayuda sería muy apreciada

Respuesta

2

@AaronMcSmooth: Me refiero a la stdout y stderr de la computadora a la que me estoy conectando (a través de SSH).

que terminé haciendo esto:

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

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

A los efectos de mi solicitud, no importa distinguir entre stdout y stderr, pero no creo que esa es la mejor manera de combinar los dos .

El código de SSHClient.exec_command() está (mirando el código fuente de 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 

estoy realizando las mismas acciones en el canal, pero recibir el canal de error es cerrado.

14

Si bien es cierto que set_combine_stderr desvía stderr a la corriente stdout, lo hace con el fin caótica, por lo que no consigue el resultado es probable que desee, es decir, las líneas combinadas en el orden escrito, como si se estuviera ejecutando el comando en una ventana de terminal local. En su lugar, use get_pty. Eso hará que el servidor ejecute las líneas a través de un pseudo-terminal, manteniéndolo en secuencia cronológica.

Aquí hay un programa de prueba, outerr.py, que escribe líneas alternas en stdout y stdin. Supongamos que está en el directorio principal de 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])) 

Ahora intenta el código siguiente para ejecutar de forma remota:

#!/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() 

Si ejecuta lo anterior, debería ver 100 líneas con el fin como está escrito. Si, en cambio, usted comenta la llamada chan.get_pty() y elimina el comentario de la llamada chan.set_combine_stderr(True), obtendrá grupos de líneas stdout y stderr intercaladas al azar de la ejecución a la ejecución.

0

Ok, sé que este es un tema bastante antiguo, pero me encuentro con el mismo problema y obtuve una (quizás no tan) bonita solución. Simplemente llame al comando en el servidor remoto redireccionando el stderr a stdout y luego siempre lea desde el stdout. Por ejemplo:

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()