Bagaimana Anda bisa mendapatkan kode pengembalian SSH menggunakan Paramiko?

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

Apakah ada cara untuk mendapatkan kode pengembalian perintah?

Sulit untuk mengurai semua stdout / stderr dan mengetahui apakah perintah berhasil diselesaikan atau tidak.

Beyonder
sumber

Jawaban:

51

SSHClient adalah kelas pembungkus sederhana di sekitar fungsionalitas yang lebih rendah di Paramiko. The dokumentasi API berisi daftar recv_exit_status()metode pada Channelkelas.

Skrip demonstrasi yang sangat sederhana:

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

Contoh pelaksanaannya:

$ 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
sumber
9
Ini adalah solusi yang buruk. Lihat jawaban @apdastous 'di bawah ini, jauh lebih baik.
Patrick
Meskipun Anda benar recv_exit_status, Anda tidak dapat menggunakannya dengan cara ini, karena kodenya mungkin menemui jalan buntu. Anda harus menggunakan output perintah, sambil menunggu perintah selesai. Lihat Paramiko ssh die / hang dengan output besar .
Martin Prikryl
283

Contoh yang jauh lebih mudah yang tidak melibatkan pemanggilan kelas saluran "tingkat bawah" secara langsung (yaitu - TIDAK menggunakan client.get_transport().open_session()perintah):

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
apdastous
sumber
5
Yang menyenangkan dari contoh ini adalah menangkap tidak hanya KELUAR (seperti pertanyaan yang diajukan), tetapi mendemonstrasikan bahwa Anda masih bisa mendapatkan STDOUT dan STDERR. Bertahun-tahun yang lalu saya disesatkan oleh basis kode contoh anemia Paramiko (tidak ada rasa tidak hormat), dan untuk mendapatkan KELUAR, saya menggunakan panggilan transportasi tingkat rendah (). transport () tampaknya memaksa Anda untuk "memilih satu" (yang mungkin tidak benar, tetapi kurangnya contoh dan dokumen tutorial membuat saya percaya bahwa) ...
Scott Prive
Meskipun Anda benar recv_exit_status, Anda tidak dapat menggunakannya dengan cara ini, karena kodenya mungkin menemui jalan buntu. Anda harus menggunakan output perintah, sambil menunggu perintah selesai. Lihat Paramiko ssh die / hang dengan output besar .
Martin Prikryl
5

Terima kasih untuk JanC, saya menambahkan beberapa modifikasi untuk contoh dan diuji dengan Python3, ini sangat berguna bagi saya.

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()
tewas
sumber
apakah kita mendapatkan pesan kesalahan -jika ada - di chan.recv_stderr_ready () ?. Apakah chan.recv_stderr (4096) .decode ('ascii') ini mengembalikan teks pesan?
kten
0

Dalam kasus saya, buffering keluaran adalah masalahnya. Karena buffering, keluaran dari aplikasi tidak keluar dengan cara non-blocking. Anda dapat menemukan jawaban tentang cara mencetak keluaran tanpa buffering di sini: Disable output buffering . Singkatnya, jalankan saja python dengan opsi -u seperti ini:

> python -u script.py

Youngmin Kim
sumber