2011-06-01 118 views
32
def exec_command(self, command, bufsize=-1): 
    #print "Executing Command: "+command 
    chan = self._transport.open_session() 
    chan.exec_command(command) 
    stdin = chan.makefile('wb', bufsize) 
    stdout = chan.makefile('rb', bufsize) 
    stderr = chan.makefile_stderr('rb', bufsize) 
    return stdin, stdout, stderr 

Al ejecutar un comando en paramiko, siempre reinicia la sesión cuando ejecuta exec_command. Quiero poder ejecutar sudo o su y todavía tengo esos privilegios cuando ejecuto otro exec_command. Otro ejemplo sería intentar ejecutar exec_command ("cd /") y luego ejecutar exec_command nuevamente y tenerlo en el directorio raíz. Sé que puedes hacer algo como exec_command ("cd /; ls -l"), pero tengo que hacerlo en llamadas a funciones separadas.¿Cómo se ejecutan varios comandos en una sola sesión en Paramiko? (Python)

Respuesta

34

casos no interactivas de uso

Ésta es una no interactiva ejemplo ... que envía cd tmp, ls y luego exit.

import sys 
sys.stderr = open('/dev/null')  # Silence silly warnings from paramiko 
import paramiko as pm 
sys.stderr = sys.__stderr__ 
import os 

class AllowAllKeys(pm.MissingHostKeyPolicy): 
    def missing_host_key(self, client, hostname, key): 
     return 

HOST = '127.0.0.1' 
USER = '' 
PASSWORD = '' 

client = pm.SSHClient() 
client.load_system_host_keys() 
client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) 
client.set_missing_host_key_policy(AllowAllKeys()) 
client.connect(HOST, username=USER, password=PASSWORD) 

channel = client.invoke_shell() 
stdin = channel.makefile('wb') 
stdout = channel.makefile('rb') 

stdin.write(''' 
cd tmp 
ls 
exit 
''') 
print stdout.read() 

stdout.close() 
stdin.close() 
client.close() 

casos de uso interactivas
Si usted tiene un caso de uso interactivo, esta respuesta no ayudarán ... Yo personalmente usaría pexpect o exscript para las sesiones interactivas.

+2

Pero esta solución no permite leer la salida del primer comando antes de que todos los comandos hayan finalizado. ¿Estoy en lo cierto? –

+1

esto no funciona porque stdout.read() lee todo el archivo. Es decir, lee el programa que fue "escrito" en la terminal. Este no es el comportamiento previsto. ¿Cómo se lee solo la salida de 'ls' en lugar de todo el programa y la salida de' ls'? –

+0

Estoy con los dos comentarios anteriores ... ¿Alguna forma de leer la salida de un comando antes de que todos los comandos hayan terminado? – dmranck

19

Estrictamente hablando, no se puede. De acuerdo con la especificación ssh:

Una sesión es una ejecución remota de un programa. El programa puede ser un shell , una aplicación, un comando del sistema o algún subsistema incorporado.

Esto significa que, una vez que se ejecuta el comando, la sesión finaliza. No puede ejecutar múltiples comandos en una sesión. Lo que PUEDE hacer, sin embargo, es iniciar un shell remoto (== un comando), e interactuar con ese shell a través de stdin, etc. ... (piense en ejecutar un script python frente al intérprete interactivo)

+1

SSH RFC no dice si la sesión debe finalizar inmediatamente después de ejecutar el comando. Si ha mirado la mayor parte del cliente ssh, siguen abriendo el Exec/Shell una vez establecida la sesión. El usuario puede escribir cualquier comando numérico. Cuando el usuario escribe "salir", solo la sesión finaliza. –

3

Intente crear una cadena de comando separada por el carácter \n. Funcionó para mí Para. p.ej. ssh.exec_command("command_1 \n command_2 \n command_3")

2
cmd = 'ls /home/dir' 
self.ssh_stdin, self.ssh_stdout, self.ssh_stderr = self.ssh.exec_command(cmd) 
print self.ssh_stdout.read() 
cmd2 = 'cat /home/dir/test.log' 
self.ssh_stdin2, self.ssh_stdout2, self.ssh_stderr2 = self.ssh.exec_command(cmd2) 
print self.ssh_stdout2.read() 
0

Puede hacer eso invocando shell en el cliente y enviando comandos. Consulte here
La página tiene código para python 3.5. He modificado un poco el código para trabajar con pythin 2.7. Agregando código aquí para referencia

import threading, paramiko 

strdata='' 
fulldata='' 

class ssh: 
    shell = None 
    client = None 
    transport = None 

    def __init__(self, address, username, password): 
     print("Connecting to server on ip", str(address) + ".") 
     self.client = paramiko.client.SSHClient() 
     self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy()) 
     self.client.connect(address, username=username, password=password, look_for_keys=False) 
     self.transport = paramiko.Transport((address, 22)) 
     self.transport.connect(username=username, password=password) 

     thread = threading.Thread(target=self.process) 
     thread.daemon = True 
     thread.start() 

    def closeConnection(self): 
     if(self.client != None): 
      self.client.close() 
      self.transport.close() 

    def openShell(self): 
     self.shell = self.client.invoke_shell() 

    def sendShell(self, command): 
     if(self.shell): 
      self.shell.send(command + "\n") 
     else: 
      print("Shell not opened.") 

    def process(self): 
     global strdata, fulldata 
     while True: 
      # Print data when available 
      if self.shell is not None and self.shell.recv_ready(): 
       alldata = self.shell.recv(1024) 
       while self.shell.recv_ready(): 
        alldata += self.shell.recv(1024) 
       strdata = strdata + str(alldata) 
       fulldata = fulldata + str(alldata) 
       strdata = self.print_lines(strdata) # print all received data except last line 

    def print_lines(self, data): 
     last_line = data 
     if '\n' in data: 
      lines = data.splitlines() 
      for i in range(0, len(lines)-1): 
       print(lines[i]) 
      last_line = lines[len(lines) - 1] 
      if data.endswith('\n'): 
       print(last_line) 
       last_line = '' 
     return last_line 


sshUsername = "SSH USERNAME" 
sshPassword = "SSH PASSWORD" 
sshServer = "SSH SERVER ADDRESS" 


connection = ssh(sshServer, sshUsername, sshPassword) 
connection.openShell() 
connection.send_shell('cmd1') 
connection.send_shell('cmd2') 
connection.send_shell('cmd3') 
time.sleep(10) 
print(strdata) # print the last line of received data 
print('==========================') 
print(fulldata) # This contains the complete data received. 
print('==========================') 
connection.close_connection() 
Cuestiones relacionadas