2010-09-29 17 views
9

Sto cercando di combinare l'output di stdout e stderr. La mia convinzione è che questo può essere fatto con il set_combine_stderr() di un oggetto Channel.paramiko combina stdout e stderr

Questo è quello che sto facendo:

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

Tuttavia, ottengo il seguente errore quando provo a memorizzare il risultato (ultima riga sopra, chan.makefile()):

Error: Channel closed.

Qualsiasi aiuto sarebbe molto apprezzato

risposta

2

@AaronMcSmooth: Mi riferisco allo stdout e allo stderr del computer con cui mi sto connettendo (tramite SSH).

ho finito per fare questo:

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

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

Ai fini della mia domanda, non importa distinguere tra stdout e stderr, ma non credo che sia il modo migliore per combinare le due cose .

Il codice di SSHClient.exec_command() è (guardando il codice sorgente di 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 

sto eseguendo le stesse azioni sul canale, ma ricevere il canale è errore chiusa.

14

Se è vero che set_combine_stderr devia stderr al flusso stdout, lo fa in modo caotico, quindi non si ottiene il risultato che probabilmente si desidera, vale a dire, le linee combinate in ordine scritto, come se si stesse eseguendo il comando in una finestra di terminale locale. Utilizzare invece get_pty. Ciò farà sì che il server esegua le linee attraverso uno pseudo-terminale, mantenendole in sequenza cronologica.

Ecco un programma di prova, outerr.py, che scrive linee alternate su stdout e stdin. Supponiamo che sia nella directory home di 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])) 

Ora provare il seguente codice per eseguire da remoto:

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

Se si esegue quanto sopra, si dovrebbe vedere 100 linee in ordine come scritta. Se, invece, commentate la chiamata chan.get_pty() e decommentate la chiamata chan.set_combine_stderr(True), otterrete gruppi di righe stdout e stderr interrotte in modo casuale da esecuzione a esecuzione.

0

Ok, so che questo è un argomento piuttosto vecchio, ma ho incontrato lo stesso problema e ho ottenuto una soluzione (forse non così) carina. Basta chiamare il comando sul server remoto reindirizzando lo stderr allo stdout e quindi sempre leggere dallo stdout. Ad esempio:

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