obtener salida de un paramiko ssh exec_command continuamente

Estoy ejecutando un script de Python de larga duración a través de ssh en una máquina remota usando paramiko. Funciona como un encanto, no hay problemas hasta ahora.

Desafortunadamente, el stdout (respectivamente el stderr) solo se muestra después de que el script haya terminado. Sin embargo, debido al tiempo de ejecución, prefiero imprimir cada nueva línea a medida que se imprime , no después.

remote = paramiko.SSHClient() remote.set_missing_host_key_policy(paramiko.AutoAddPolicy()) remote.connect("host", username="uname", password="pwd") # myScript produces continuous output, that I want to capture as it appears stdin, stdout, stderr = remote.exec_command("python myScript.py") stdin.close() for line in stdout.read().splitlines(): print(line) 

¿Cómo se puede lograr esto? Nota: por supuesto, uno podría canalizar la salida a un archivo y ‘menos’ este archivo a través de otra sesión ssh, pero esto es muy feo y necesito una solución más limpia e idealmente pythonica 🙂

Como se especifica en la documentación de lectura ( [tamaño] ) , si no especifica un size , lee hasta EOF, lo que hace que el script espere hasta que el comando finalice antes de regresar de read() e imprimir cualquier salida.

Verifique estas respuestas: ¿Cómo hacer un bucle hasta EOF en Python? y Cómo hacer un “Si bien no es EOF” para obtener ejemplos sobre cómo agotar el objeto similar a un archivo.

Me enfrentaba a un problema similar. Pude resolverlo agregando get_pty = True a paramiko:

 stdin, stdout, stderr = client.exec_command("/var/mylongscript.py", get_pty=True) 

Un ejemplo de trabajo mínimo y completo sobre cómo usar esta respuesta (probado en Python 3.6.1)

 # run.py from paramiko import SSHClient ssh = SSHClient() ssh.load_system_host_keys() ssh.connect('...') print('started...') stdin, stdout, stderr = ssh.exec_command('python -m example', get_pty=True) for line in iter(stdout.readline, ""): print(line, end="") print('finished.') 

y

 # example.py, at the server import time for x in range(10): print(x) time.sleep(2) 

ejecutar en la máquina local con

 python -m run