¿Cómo se puede obtener el código de retorno SSH usando Paramiko?


97
client = paramiko.SSHClient()
stdin, stdout, stderr = client.exec_command(command)

¿Hay alguna forma de obtener el código de retorno del comando?

Es difícil analizar todos los stdout / stderr y saber si el comando finalizó correctamente o no.

Respuestas:


51

SSHClient es una clase contenedora simple alrededor de la funcionalidad de nivel más bajo en Paramiko. La documentación de la API enumera un método recv_exit_status () en la clase Channel.

Un guión de demostración muy simple:

$ cat sshtest.py
import paramiko
import getpass

pw = getpass.getpass()

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect('127.0.0.1', password=pw)

while True:
    cmd = raw_input("Command to run: ")
    if cmd == "":
        break
    chan = client.get_transport().open_session()
    print "running '%s'" % cmd
    chan.exec_command(cmd)
    print "exit status: %s" % chan.recv_exit_status()

client.close()

$ python sshtest.py
Password: 
Command to run: true
running 'true'
exit status: 0
Command to run: false
running 'false'
exit status: 1
Command to run: 
$

Realmente agradezco tu respuesta !! Lo he usado en mi proyecto. Muchas gracias. Hasta ahora puedo usar paramiko en lugar de ajustar el comando del sistema ssh en la programación con python.
Beyonder

Es solo algo que armé al mirar la fuente de SSHClient, por lo que puede que no sea óptimo . Por cierto: si esto hace lo que quieres, es posible que desees "aceptar" mi respuesta.
JanC

Link Dead Please Update
bhathiya-perera

3
chan.recv_exit_status () - encantador cuando esto simplemente se cuelga y nunca regresa. Buen consejo.
aaa90210

9
Ésta es una mala solución. Vea la respuesta de @apdastous a continuación, es mucho mejor.
Patrick

282

Un ejemplo mucho más fácil que no implica invocar directamente la clase de canal de "nivel inferior" (es decir, NO usar el client.get_transport().open_session()comando):

import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('blahblah.com')

stdin, stdout, stderr = client.exec_command("uptime")
print stdout.channel.recv_exit_status()    # status is 0

stdin, stdout, stderr = client.exec_command("oauwhduawhd")
print stdout.channel.recv_exit_status()    # status is 127

5
Lo bueno de este ejemplo es capturar no solo EXIT (como se pregunta en la pregunta), sino demostrar que aún puede obtener STDOUT y STDERR. Hace años, fui engañado por la base de código de ejemplo anémica de Paramiko (sin faltarle el respeto), y para obtener EXIT recurrí a llamadas de transporte () de bajo nivel. transport () parecía forzarte a "elegir uno" (lo cual puede no ser cierto, pero la falta de ejemplos y documentos tutoriales me llevó a creer eso) ...
Scott Prive

Si bien está en lo correcto recv_exit_status, no puede usarlo de esta manera, ya que el código puede bloquearse. Tienes que consumir la salida del comando, mientras esperas a que termine el comando. Vea Paramiko ssh morir / colgar con gran salida .
Martin Prikryl hace

5

Gracias por JanC, agregué algunas modificaciones para el ejemplo y lo probé en Python3, fue realmente útil para mí.

import paramiko
import getpass

pw = getpass.getpass()

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
#client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def start():
    try :
        client.connect('127.0.0.1', port=22, username='ubuntu', password=pw)
        return True
    except Exception as e:
        #client.close()
        print(e)
        return False

while start():
    key = True
    cmd = input("Command to run: ")
    if cmd == "":
        break
    chan = client.get_transport().open_session()
    print("running '%s'" % cmd)
    chan.exec_command(cmd)
    while key:
        if chan.recv_ready():
            print("recv:\n%s" % chan.recv(4096).decode('ascii'))
        if chan.recv_stderr_ready():
            print("error:\n%s" % chan.recv_stderr(4096).decode('ascii'))
        if chan.exit_status_ready():
            print("exit status: %s" % chan.recv_exit_status())
            key = False
            client.close()
client.close()

¿Recibimos algún mensaje de error, si lo hay, en chan.recv_stderr_ready () ?. ¿Chan.recv_stderr (4096) .decode ('ascii') devuelve un mensaje de texto?
kten

0

En mi caso, el búfer de salida fue el problema. Debido al almacenamiento en búfer, las salidas de la aplicación no salen sin bloqueo. Puede encontrar la respuesta sobre cómo imprimir la salida sin almacenar en búfer aquí: Desactive el almacenamiento en búfer de salida . Para abreviar, simplemente ejecute python con la opción -u como esta:

> python -u script.py

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.