Подтвердить что ты не робот

Долгосрочные команды ssh в модуле python paramiko (и как их закончить)

Я хочу запустить команду tail -f logfile на удаленном компьютере с использованием модуля python paramiko. Я делаю это до сих пор следующим образом:

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

Я бы хотел, чтобы команда выполнялась столько, сколько необходимо, но у меня есть две проблемы:

  • Как я могу прекратить это чисто? Я подумал о создании канала, а затем с помощью команды shutdown() на канале, когда я закончил с ним, но это кажется беспорядочным. Возможно ли сделать что-то вроде отправки Ctrl-C на канал stdin?
  • readline(), и я мог бы избежать потоков, если бы у меня был неблокирующий метод получения вывода - любые мысли?
4b9b3361

Ответ 1

1) Вы можете просто закрыть клиента, если хотите. Сервер с другого конца убьет хвостовой процесс.

2) Если вам нужно сделать это неблокирующим способом, вам придется напрямую использовать объект канала. Затем вы можете смотреть как stdout, так и stderr с каналами .recv_ready() и channel.recv_stderr_ready() или использовать select.select.

Ответ 2

Вместо вызова exec_command на клиенте возьмите транспорт и создайте собственный канал. channel можно использовать для выполнения команды, и вы можете использовать ее в инструкции select, чтобы узнать, когда данные могут быть прочитаны:

#!/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)

Объект канала можно считывать и записывать, подключаясь к stdout и stdin удаленной команды. Вы можете получить stderr, вызвав channel.makefile_stderr(...).

Я установил таймаут на 0.0 секунды, потому что было запрошено неблокирующее решение. В зависимости от ваших потребностей вы можете блокировать с ненулевым тайм-аутом.

Ответ 3

Просто небольшое обновление для решения Эндрю Айлетта. Следующий код фактически прерывает цикл и завершает работу, когда внешний процесс завершается:

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)

Ответ 4

Чтобы закрыть процесс, просто запустите:

interface.close()

В терминах неблокирования вы не можете получить неблокирующее чтение. Лучшее, что вы могли бы сделать, - разобрать на нем один "блок" за раз, "stdout.read(1)" будет блокироваться только тогда, когда в буфере нет символов.

Ответ 5

Просто для информации есть решение сделать это с помощью channel.get_pty(). Более подробная информация приведена ниже: fooobar.com/info/241655/...