Длительно выполняющиеся ssh-команды в модуле python paramiko (и как их завершить)
Вопрос
Я хочу запустить tail -f logfile
команда на удаленном компьютере с использованием модуля paramiko на python.До сих пор я пытался сделать это следующим образом:
interface = paramiko.SSHClient()
#snip the connection setup portion
stdin, stdout, stderr = interface.exec_command("tail -f logfile")
#snip into threaded loop
print stdout.readline()
Я бы хотел, чтобы команда выполнялась столько, сколько необходимо, но у меня есть 2 проблемы:
- Как мне остановить это чисто?Я подумал о том, чтобы создать Канал, а затем использовать
shutdown()
команда на канале, когда я закончу с этим - но это кажется запутанным.Можно ли сделать что-то вроде отправленногоCtrl-C
к stdin канала? readline()
блоки, и я мог бы избежать потоков, если бы у меня был неблокирующий метод получения выходных данных - есть какие-нибудь мысли?
Решение
1) Вы можете просто закрыть клиент, если хотите.Сервер на другом конце остановит конечный процесс.
2) Если вам нужно сделать это неблокирующим способом, вам придется напрямую использовать объект channel.Затем вы можете отслеживать как stdout, так и stderr с помощью channel.recv_ready() и channel.recv_stderr_ready() или использовать select.select.
Другие советы
Вместо вызова exec_command на клиенте, получите доступ к транспорту и сгенерируйте свой собственный канал.В канал может использоваться для выполнения команды, и вы можете использовать его в инструкции 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)
Объект channel можно считывать и записывать, подключаясь с помощью stdout и stdin удаленной команды.Вы можете получить доступ к stderr, позвонив channel.makefile_stderr(...)
.
Я установил тайм-аут на 0.0
секунд, потому что было запрошено неблокирующее решение.В зависимости от ваших потребностей, вы можете захотеть заблокировать с ненулевым таймаутом.
Просто небольшое обновление решения Эндрю Эйлетта.Следующий код фактически прерывает цикл и завершается, когда внешний процесс завершается:
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)
Чтобы закрыть процесс, просто запустите:
interface.close()
С точки зрения неблокирующего, вы не можете получить неблокирующее чтение.Лучшее, что вы могли бы сделать, это анализировать его по одному "блоку" за раз, "stdout.read(1)" будет блокироваться только тогда, когда в буфере не останется символов.
Просто для информации, есть решение сделать это с помощью channel.get_pty().Для получения более подробной информации взгляните на: https://stackoverflow.com/a/11190727/1480181