Les commandes SSH en cours depuis longtemps dans le module paramiko de python (et comment les terminer)

je veux exécuter un tail -f logfile commande sur une machine distante en utilisant le module paramiko de python. J'ai essayé jusqu'à présent de la manière suivante:

interface = paramiko.SSHClient()
#snip the connection setup portion
stdin, stdout, stderr = interface.exec_command("tail -f logfile")
#snip into threaded loop
print stdout.readline()

j'aimerais que la commande fonctionne aussi longtemps que nécessaire, mais j'ai 2 problèmes:

  1. Comment puis-je arrêter cela proprement? J'ai pensé à faire un Canal, puis à l'aide de la shutdown() commande sur la chaîne quand j'en ai fini avec elle - mais cela semble désordonné. Est-il possible de faire quelque chose comme envoyé Ctrl-C pour le canal d'entrée standard stdin?
  2. readline() blocs, et j'ai pu éviter les threads si j'avais une méthode non bloquante de l'obtention de la sortie - une idée?
21
demandé sur user17925 2009-04-17 19:51:20

5 réponses

1) vous pouvez simplement fermer le client si vous le souhaitez. Le serveur de l'autre côté va tuer le processus de queue.

2) Si vous devez le faire de manière non-bloquante, vous devrez utiliser l'objet channel directement. Vous pouvez alors regarder à la fois stdout et stderr avec channel.recv_ready() et le canal.recv_stderr_ready (), ou utilisez select.sélectionner.

14
répondu JimB 2009-05-07 17:43:22

au lieu d'appeler exec_command sur le client, saisissez le transport et créez votre propre canal. canal peut être utilisée pour exécuter une commande, et vous pouvez l'utiliser dans une instruction select pour savoir quand les données peuvent être lues comme suit:

#!/usr/bin/env python
import paramiko
import select
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('host.example.com')
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command("tail -f /var/log/everything/current")
while True:
  rl, wl, xl = select.select([channel],[],[],0.0)
  if len(rl) > 0:
      # Must be stdout
      print channel.recv(1024)

l'objet channel peut être lu et écrit, se connectant avec stdout et stdin de la commande à distance. Vous pouvez vous rendre à stderr en appelant channel.makefile_stderr(...).

j'ai définissez le délai de 0.0 secondes parce qu'un une solution non bloquante a été demandée. Selon vos besoins, vous pouvez bloquer avec un délai non nul.

21
répondu Andrew Aylett 2016-07-13 19:43:27

Juste une petite mise à jour de la solution par Andrew Aylett. Le code suivant casse la boucle et quitte la boucle lorsque le processus externe se termine:

import paramiko
import select

client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('host.example.com')
channel = client.get_transport().open_session()
channel.exec_command("tail -f /var/log/everything/current")
while True:
    if channel.exit_status_ready():
        break
    rl, wl, xl = select.select([channel], [], [], 0.0)
    if len(rl) > 0:
        print channel.recv(1024)
7
répondu Anton Beloglazov 2013-02-15 04:40:38

Pour fermer le processus est tout simplement d'exécuter:

interface.close()

en termes de non-blocage, vous ne pouvez pas obtenir une lecture non-bloquante. Le meilleur vous seriez capable de s'analyser sur un "bloc" à un moment, "stdout.read (1) " ne bloquera que s'il ne reste plus de caractères dans le tampon.

0
répondu lfaraone 2009-04-18 00:58:10

juste pour information, il y a une solution pour le faire en utilisant channel.get_pty (). Pour plus de détails, veuillez consulter: https://stackoverflow.com/a/11190727/1480181

0
répondu Sven 2017-05-23 12:02:34