2009-04-17 19 views
21

我想使用python的paramiko模塊在遠程計算機上運行tail -f logfile命令。我一直到目前爲止,它試圖以下列方式:python paramiko模塊中的長時間運行的ssh命令(以及如何結束它們)

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個問題:

  1. 如何停止該乾淨?我想要製作一個頻道,然後在頻道上使用shutdown()命令,但這似乎很麻煩。是否可以做一些事情,如發送Ctrl-C到頻道的stdin?
  2. readline()塊,我可以避免線程,如果我有一個非阻塞方法獲取輸出 - 任何想法?
+0

討厭打破壞消息,但SSHClient()已在內部使用線程。 – joeforker 2009-05-12 20:20:35

回答

14

1)如果您願意,您可以關閉客戶端。另一端的服務器將終止尾部進程。

2)如果您需要以非阻塞的方式執行此操作,則必須直接使用通道對象。然後,您可以使用channel.recv_ready()和channel.recv_stderr_ready()注意stdout和stderr,或使用select.select。

0

關閉該進程,只需運行:

interface.close() 

在非阻塞而言,你不能得到非阻塞讀。最好的辦法是一次解析一個「塊」,「stdout.read(1)」只會在緩衝區中沒有剩餘字符的情況下阻塞。

21

而不是調用客戶端上的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) 

通道對象可以被讀出和寫入,與標準輸出連接和遠程命令的標準輸入。您可以致電channel.makefile_stderr(...)來獲得stderr。

我已將超時設置爲0.0秒,因爲請求了非阻塞解決方案。根據您的需要,您可能希望以非零超時進行阻止。

+0

你不能選擇stdout對象,因爲它缺少fileno屬性。 goathens不使用頻道對象。 – JimB 2009-05-07 17:33:07

+0

我修改並擴展了示例,並對其進行了測試,以確保它能夠正常工作:)。 – 2009-06-10 23:12:04

+0

這是否也適用於stderr,如果你用xl替換rl? – 2012-06-27 10:42:13

6

只是Andrew Aylett對解決方案的小小更新。下面的代碼實際上打破了循環,並在外部進程結束時退出:

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) 
相關問題