Come puoi ottenere il codice di ritorno SSH usando Paramiko?


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

C'è un modo per ottenere il codice di ritorno del comando?

È difficile analizzare tutti gli stdout / stderr e sapere se il comando è stato completato correttamente o meno.

Risposte:


51

SSHClient è una semplice classe wrapper attorno alle funzionalità di livello inferiore in Paramiko. La documentazione API elenca un recv_exit_status()metodo sulla Channelclasse.

Uno script dimostrativo molto semplice:

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

Esempio della sua esecuzione:

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

9
Questa è una cattiva soluzione. Vedi la risposta di @apdastous di seguito, è molto meglio.
Patrick

Sebbene tu abbia ragione recv_exit_status, non puoi usarlo in questo modo, poiché il codice potrebbe bloccarsi. Devi consumare l'output del comando, mentre aspetti che il comando finisca. Vedere Paramiko ssh die / hang with big output .
Martin Prikryl il

283

Un esempio molto più semplice che non implica l'invocazione diretta della classe del canale "livello inferiore" (cioè, NON usare il 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
La cosa bella di questo esempio è catturare non solo EXIT (come la domanda chiede), ma dimostrare che puoi ancora ottenere STDOUT e STDERR. Anni fa sono stato fuorviato dal codebase di esempio anemico di Paramiko (senza mancare di rispetto), e per ottenere EXIT ho fatto ricorso a chiamate transport () di basso livello. transport () sembrava costringerti a "sceglierne uno" (il che potrebbe non essere vero, ma la mancanza di esempi e documenti tutorial mi ha portato a credere che) ...
Scott Prive

Sebbene tu abbia ragione recv_exit_status, non puoi usarlo in questo modo, poiché il codice potrebbe bloccarsi. Devi consumare l'output del comando, mentre aspetti che il comando finisca. Vedere Paramiko ssh die / hang with big output .
Martin Prikryl il

5

Grazie per JanC, ho aggiunto alcune modifiche all'esempio e l'ho testato in Python3, è davvero utile per me.

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

riceviamo messaggi di errore, se ce ne sono, in chan.recv_stderr_ready () ?. Chan.recv_stderr (4096) .decode ('ascii') this restituisce un messaggio di testo?
kten

0

Nel mio caso, il problema era il buffering dell'output. A causa del buffering, gli output dell'applicazione non escono in modo non bloccante. Puoi trovare la risposta su come stampare l'output senza buffering qui: Disabilita il buffering dell'output . In breve, esegui python con l'opzione -u come questa:

> python -u script.py

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.