Como você pode obter o código de retorno SSH usando Paramiko?


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

Existe alguma maneira de obter o código de retorno do comando?

É difícil analisar todos os stdout / stderr e saber se o comando foi concluído com êxito ou não.

Respostas:


51

SSHClient é uma classe de wrapper simples em torno da funcionalidade de nível mais baixo no Paramiko. A documentação da API lista um recv_exit_status()método da Channelclasse.

Um script de demonstração muito simples:

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

Exemplo de sua execução:

$ 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
Esta é uma solução ruim. Veja a resposta @apdastous 'abaixo, é muito melhor.
Patrick

Embora você esteja correto sobre recv_exit_status, você não pode usá-lo dessa forma, pois o código pode travar. Você tem que consumir a saída do comando, enquanto espera a conclusão do comando. Veja Paramiko ssh die / hang com grande saída .
Martin Prikryl

283

Um exemplo muito mais fácil que não envolve invocar a classe de canal de "nível inferior" diretamente (ou seja - NÃO usar o 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
O que é bom neste exemplo é capturar não apenas EXIT (como a pergunta pergunta), mas demonstrar que você ainda pode obter STDOUT e STDERR. Anos atrás, fui enganado pelo anêmico exemplo de base de código de Paramiko (sem desrespeito) e, para obter EXIT, recorri a chamadas de transporte () de baixo nível. transport () pareceu forçá-lo a "escolher um" (o que pode não ser verdade, mas a falta de exemplos e documentos tutoriais me levou a acreditar nisso) ...
Scott Prive

Embora você esteja correto sobre recv_exit_status, você não pode usá-lo dessa forma, pois o código pode travar. Você tem que consumir a saída do comando, enquanto espera a conclusão do comando. Veja Paramiko ssh die / hang com grande saída .
Martin Prikryl

5

Obrigado por JanC, eu adicionei algumas modificações para o exemplo e testei em Python3, é realmente útil para mim.

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

recebemos alguma mensagem de erro, se houver, em chan.recv_stderr_ready () ?. O chan.recv_stderr (4096) .decode ('ascii') retorna um texto de mensagem?
kten

0

No meu caso, o buffer de saída era o problema. Por causa do buffering, as saídas do aplicativo não saem de maneira não bloqueadora. Você pode encontrar a resposta sobre como imprimir saída sem buffer aqui: Desative o buffer de saída . Resumindo, basta executar python com a opção -u como esta:

> python -u script.py

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.