2012-05-24 14 views
10

Ich bin neu auf Python. Ich schrieb ein Skript zu einem Host zu verbinden und führen Sie einen BefehlPython Paramiko SSH

ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(host, username=user, password=pw) 

print 'running remote command' 

stdin, stdout, stderr = ssh.exec_command(command) 
stdin.close() 

for line in stdout.read().splitlines(): 
    print '%s$: %s' % (host, line) 
    if outfile != None: 
     f_outfile.write("%s\n" %line) 

for line in stderr.read().splitlines(): 
    print '%s$: %s' % (host, line + "\n") 
    if outfile != None: 
     f_outfile.write("%s\n" %line) 

ssh.close() 

if outfile != None: 
    f_outfile.close() 

print 'connection to %s closed' %host 

except: 
    e = sys.exc_info()[1] 
    print '%s' %e 

funktioniert gut, wenn dann Remote-Befehl kein tty benötigen. Ich habe ein invoke_shell Beispiel Nested SSH session with Paramiko gefunden. Ich bin nicht glücklich mit dieser Lösung, denn wenn ein Server eine Eingabeaufforderung hat, die nicht in meinem Skript angegeben ist -> Endlosschleife oder eine angegebene Eingabeaufforderung im Skript ist eine Zeichenfolge im Rückgabentext -> werden nicht alle Daten empfangen . Gibt es eine bessere Lösung, wo Stdout und Stderr wie in meinem Skript zurückgeschickt werden?

Antwort

11

Es gibt umfangreiche paramiko API-Dokumentation finden Sie unter: http://docs.paramiko.org/en/stable/index.html

ich die folgende Methode verwenden, um Befehle auf einem passwortgeschützten Client auszuführen:

import paramiko 
import sys 

nbytes = 4096 
hostname = 'hostname' 
port = 22 
username = 'username' 
password = 'password' 
command = 'ls' 

client = paramiko.Transport((hostname, port)) 
client.connect(username=username, password=password) 

stdout_data = [] 
stderr_data = [] 
session = client.open_channel(kind='session') 
session.exec_command(command) 
while True: 
    if session.recv_ready(): 
     stdout_data.append(session.recv(nbytes)) 
    if session.recv_stderr_ready(): 
     stderr_data.append(session.recv_stderr(nbytes)) 
    if session.exit_status_ready(): 
     break 

print 'exit status: ', session.recv_exit_status() 
print ''.join(stdout_data) 
print ''.join(stderr_data) 

session.close() 
client.close() 
+1

statt 'data_block' man zum Beispiel verwenden' session.recv (4096) 'und' session.recv_stderr (4096) 'sollten (wo die' hat data_block' kommen?). –

+0

Sie haben Recht, der data_block war wie beschrieben (recv/recv_stderr), aber ich habe diese Zeilen versehentlich gelöscht. – ThePracticalOne

+0

Ab Mai 2015 sind die Paramiko-Dokumente [hier] (http://docs.paramiko.org/en/1.15/index.html) – Jeremiah

7

Es ist etwas falsch mit der akzeptierte Antwort ist, Es bringt manchmal (zufällig) eine abgeschnittene Antwort vom Server. Ich weiß nicht, warum ich nicht die fehlerhafte Ursache für die akzeptierte Antwort untersuchen habe, weil dieser Code perfekt für mich gearbeitet:

import paramiko 

ip='server ip' 
port=22 
username='username' 
password='password' 

cmd='some useful command' 

ssh=paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(ip,port,username,password) 

stdin,stdout,stderr=ssh.exec_command(cmd) 
outlines=stdout.readlines() 
resp=''.join(outlines) 
print(resp) 

stdin,stdout,stderr=ssh.exec_command('some really useful command') 
outlines=stdout.readlines() 
resp=''.join(outlines) 
print(resp) 
+0

Ich habe auch gesehen, es ist wie eine Race-Bedingung mit exit_status_ready() und recv_ready() – robert

0

Der Code von @ThePracticalOne ist ideal für die Verwendung mit einer Ausnahme zeigt: somtimes der Ausgang wäre unvollständig. (session.recv_ready() dreht wahr, nachdem die if session.recv_ready(): während session.recv_stderr_ready() und session.exit_status_ready() wahr geworden vor der nächsten Schleife eintritt)

so mein Denken auf das Abrufen der Daten ist, wenn sie bereit ist, um die Sitzung zu beenden.

while True: 
if session.exit_status_ready(): 
while True: 
    while True: 
     print "try to recv stdout..." 
     ret = session.recv(nbytes) 
     if len(ret) == 0: 
      break 
     stdout_data.append(ret) 

    while True: 
     print "try to recv stderr..." 
     ret = session.recv_stderr(nbytes) 
     if len(ret) == 0: 
      break 
     stderr_data.append(ret) 
    break 
Verwandte Themen