คุณจะได้รับรหัสส่งคืน SSH โดยใช้ Paramiko ได้อย่างไร?


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

มีวิธีใดในการรับโค้ดส่งคืนคำสั่งหรือไม่?

ยากที่จะแยกวิเคราะห์ stdout / stderr ทั้งหมดและรู้ว่าคำสั่งเสร็จสมบูรณ์หรือไม่

คำตอบ:


52

SSHClient เป็นคลาส Wrapper ที่เรียบง่ายรอบ ๆ ฟังก์ชันการทำงานระดับล่างใน Paramiko เอกสาร APIแสดงรายการrecv_exit_status()วิธีการในChannelชั้นเรียน

สคริปต์การสาธิตที่ง่ายมาก:

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

9
นี่เป็นทางออกที่ไม่ดี ดูคำตอบของ @apdastous ด้านล่างจะดีกว่ามาก
Patrick

แม้ว่าคุณจะถูกต้องrecv_exit_statusคุณไม่สามารถใช้วิธีนี้ได้เนื่องจากรหัสอาจหยุดชะงัก คุณต้องใช้เอาต์พุตคำสั่งในขณะที่รอให้คำสั่งเสร็จสิ้น ดูParamiko SSH ตาย / แขวนกับการส่งออกขนาดใหญ่
Martin Prikryl

292

ตัวอย่างที่ง่ายกว่ามากที่ไม่เกี่ยวข้องกับการเรียกใช้คลาสแชนเนล "ระดับล่าง" โดยตรง (เช่น - ไม่ใช้client.get_transport().open_session()คำสั่ง):

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
สิ่งที่ดีเกี่ยวกับตัวอย่างนี้คือการจับภาพไม่ใช่แค่ EXIT (เช่นคำถามที่ถาม) แต่แสดงให้เห็นว่าคุณยังสามารถรับ STDOUT และ STDERR ได้ หลายปีที่แล้วฉันหลงผิดโดยโค้ดเบสตัวอย่างโรคโลหิตจางของ Paramiko (ไม่ดูหมิ่น) และเพื่อให้ EXIT ฉันใช้การโทรระดับต่ำ () transport () ดูเหมือนจะบังคับให้คุณ "เลือกอย่างใดอย่างหนึ่ง" (ซึ่งอาจไม่เป็นความจริง แต่การขาดตัวอย่างและเอกสารการสอนทำให้ฉันเชื่อเช่นนั้น) ...
Scott Prive

แม้ว่าคุณจะถูกต้องrecv_exit_statusคุณไม่สามารถใช้วิธีนี้ได้เนื่องจากรหัสอาจหยุดชะงัก คุณต้องใช้เอาต์พุตคำสั่งในขณะที่รอให้คำสั่งเสร็จสิ้น ดูParamiko SSH ตาย / แขวนกับการส่งออกขนาดใหญ่
Martin Prikryl

5

ขอบคุณสำหรับ JanC ฉันได้เพิ่มการปรับเปลี่ยนบางอย่างสำหรับตัวอย่างและทดสอบใน Python3 มันมีประโยชน์สำหรับฉันจริงๆ

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

เราได้รับข้อความแสดงข้อผิดพลาดหรือไม่ - ใน chan.recv_stderr_ready () หรือไม่? chan.recv_stderr (4096) .decode ('ascii') ส่งคืนข้อความหรือไม่
kten

0

ในกรณีของฉันการบัฟเฟอร์เอาต์พุตเป็นปัญหา เนื่องจากการบัฟเฟอร์ผลลัพธ์จากแอปพลิเคชันจะไม่ออกมาแบบไม่ปิดกั้น คุณสามารถหาคำตอบเกี่ยวกับวิธีการพิมพ์การส่งออกโดยไม่ต้องบัฟเฟอร์ที่นี่: บัฟเฟอร์ส่งออกปิดการใช้งาน ในระยะสั้นเพียงแค่เรียกใช้ python ด้วย -u ตัวเลือกดังนี้:

> python -u script.py

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.