112 votes

Comment obtenir le code de retour SSH en utilisant Paramiko ?

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

Y a-t-il un moyen d'obtenir le code de retour de la commande ?

Il est difficile d'analyser tous les stdout/stderr et de savoir si la commande s'est terminée avec succès ou non.

339voto

apdastous Points 531

Un exemple beaucoup plus simple qui n'implique pas d'invoquer directement la classe de canal "de niveau inférieur" (c'est-à-dire - PAS en utilisant le client.get_transport().open_session() commande) :

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 votes

Qu'est-ce que joli L'intérêt de cet exemple est de capturer non seulement EXIT (comme le demande la question), mais de démontrer que vous pouvez toujours obtenir STDOUT et STDERR. Il y a des années, j'ai été induit en erreur par la base de code d'exemple anémique de Paramiko (sans vouloir manquer de respect), et pour obtenir EXIT, j'ai eu recours à des appels de bas niveau de transport(). transport() semblait vous forcer à "en choisir un" (ce qui n'est peut-être pas vrai, mais le manque d'exemples et de documentation du tutoriel m'a amené à le croire)...

0 votes

Bien que vous ayez raison au sujet recv_exit_status vous ne pouvez pas l'utiliser de cette façon, car le code pourrait se bloquer. Vous devez consommer la sortie de la commande, en attendant que la commande se termine. Voir Paramiko ssh die/hang avec gros rendement .

53voto

JanC Points 722

SSHClient est une simple classe d'enveloppe autour de la fonctionnalité de plus bas niveau de Paramiko. Le site Documentation de l'API liste un recv_exit_status() sur la méthode Channel classe.

Une démonstration très simple script :

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

Exemple de son exécution :

$ 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: 
$

13 votes

C'est une mauvaise solution. Voir la réponse de @apdastous ci-dessous, elle est bien meilleure.

1 votes

Bien que vous ayez raison au sujet recv_exit_status vous ne pouvez pas l'utiliser de cette façon, car le code pourrait se bloquer. Vous devez consommer la sortie de la commande, en attendant que la commande se termine. Voir Paramiko ssh die/hang avec gros rendement .

5voto

perillaseed Points 31

Merci pour JanC, j'ai ajouté quelques modifications pour l'exemple et testé en Python3, c'est vraiment utile pour moi.

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

0 votes

Est-ce qu'on obtient un message d'erreur - s'il y en a un - dans chan.recv_stderr_ready() ? Est-ce que chan.recv_stderr(4096).decode('ascii') renvoie un texte de message ?

0voto

Youngmin Kim Points 93

Dans mon cas, la mise en mémoire tampon des sorties était le problème. À cause de la mise en mémoire tampon, les sorties de l'application ne sortent pas de manière non bloquante. Vous pouvez trouver la réponse à la question de savoir comment imprimer la sortie sans mise en mémoire tampon ici : Désactiver la mise en mémoire tampon de la sortie . Pour faire court, il suffit de lancer python avec l'option -u comme ceci :

> python -u script.py

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X