Wie können Sie den SSH-Rückkehrcode mit Paramiko erhalten?

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

Gibt es eine Möglichkeit, den Befehlsrückgabecode abzurufen?

Es ist schwierig, alle stdout / stderr zu analysieren und zu wissen, ob der Befehl erfolgreich abgeschlossen wurde oder nicht.

Jenseits
quelle

Antworten:

51

SSHClient ist eine einfache Wrapper-Klasse, die sich mit den Funktionen auf niedrigerer Ebene in Paramiko befasst. In der API-Dokumentation wird eine recv_exit_status () -Methode für die Channel-Klasse aufgeführt.

Ein sehr einfaches Demonstrationsskript:

$ 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: 
$
JanC
quelle
Wirklich dankbar für Ihre Antwort! Ich habe es in meinem Projekt verwendet. Vielen Dank. Bisher kann ich paramiko verwenden, anstatt den Systembefehl ssh in die Programmierung mit Python einzuschließen.
Jenseits des
Es ist nur etwas, das ich zusammengestellt habe, indem ich mir die Quelle von SSHClient angesehen habe, daher ist es möglicherweise nicht optimal . Übrigens: Wenn dies das tut, was Sie wollen, möchten Sie vielleicht meine Antwort "akzeptieren".
JanC
Link Dead Please Update
Bhathiya-Perera
3
chan.recv_exit_status () - schön, wenn dies nur hängt und nie zurückkehrt. Guter Hinweis.
aaa90210
9
Dies ist eine schlechte Lösung. Siehe @apdastous 'Antwort unten, es ist viel besser.
Patrick
282

Ein viel einfacheres Beispiel, bei dem die Kanalklasse "unterer Ebene" nicht direkt aufgerufen wird (dh - der client.get_transport().open_session()Befehl NICHT verwendet wird ):

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
schrecklich
quelle
5
Das Schöne an diesem Beispiel ist, nicht nur EXIT zu erfassen (wie in der Frage gestellt), sondern zu demonstrieren, dass Sie immer noch STDOUT und STDERR erhalten können. Vor Jahren wurde ich von Paramikos anämischer Beispielcodebasis (keine Respektlosigkeit) in die Irre geführt, und um EXIT zu erhalten, griff ich auf Low-Level-Transport () -Aufrufe zurück. transport () schien Sie zu zwingen, "eine auszuwählen" (was vielleicht nicht wahr ist, aber das Fehlen von Beispielen und Tutorial-Dokumenten ließ mich das glauben) ...
Scott Prive
5

Vielen Dank für JanC, ich habe einige Änderungen für das Beispiel hinzugefügt und in Python3 getestet, es ist wirklich nützlich für mich.

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()
perillaseed
quelle
erhalten wir eine Fehlermeldung - falls vorhanden - in chan.recv_stderr_ready ()?. Gibt chan.recv_stderr (4096) .decode ('ascii') einen Nachrichtentext zurück?
Kten
0

In meinem Fall war die Ausgabepufferung das Problem. Aufgrund der Pufferung werden die Ausgaben der Anwendung nicht blockierend ausgegeben. Die Antwort zum Drucken von Ausgaben ohne Pufferung finden Sie hier: Deaktivieren Sie die Ausgabepufferung . Kurz gesagt, führen Sie Python einfach mit der folgenden Option -u aus:

> python -u script.py

Youngmin Kim
quelle