2009-04-17 36 views
21

Tôi muốn chạy lệnh tail -f logfile trên máy từ xa bằng mô-đun paramiko của python. Tôi đã cố gắng nó cho đến nay trong thời trang sau:Lệnh ssh chạy dài trong mô-đun paramiko python (và cách kết thúc chúng)

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

Tôi muốn các lệnh để chạy miễn là cần thiết, nhưng tôi có 2 vấn đề:

  1. Làm thế nào để ngăn chặn điều này sạch? Tôi đã nghĩ đến việc tạo một Kênh và sau đó sử dụng lệnh shutdown() trên kênh khi tôi kết nối với nó - nhưng điều đó có vẻ lộn xộn. Có thể thực hiện điều gì đó như đã gửi Ctrl-C tới kênh chuẩn của kênh không?
  2. readline() khối và tôi có thể tránh các chuỗi nếu tôi có phương pháp không chặn đầu ra - bất kỳ suy nghĩ nào?
+0

Ghét để phá vỡ tin xấu, nhưng SSHClient() đã sử dụng chủ đề nội bộ. – joeforker

Trả lời

14

1) Bạn chỉ có thể đóng ứng dụng nếu muốn. Máy chủ ở đầu kia sẽ giết quá trình đuôi.

2) Nếu bạn cần thực hiện điều này theo cách không chặn, bạn sẽ phải trực tiếp sử dụng đối tượng kênh. Sau đó, bạn có thể xem cả stdout và stderr với channel.recv_ready() và channel.recv_stderr_ready() hoặc sử dụng select.select.

+1

Tôi đến muộn bên, nhưng không phải là 'exec_command' chính nó không chặn? – zengr

+1

Bạn nói đúng, nhưng câu hỏi hỏi về 'readline()'. – Dan

+1

Trên một số máy chủ mới hơn, quy trình của bạn sẽ không bị giết ngay cả sau khi bạn chấm dứt khách hàng của mình. Bạn phải đặt 'get_pty = True' trong' exec_command() 'để các tiến trình được dọn sạch sau khi thoát khỏi máy khách. – nlsun

0

Để đóng quá trình này chỉ cần chạy:

interface.close() 

Về nonblocking, bạn có thể không nhận được một nonblocking đọc. Tốt nhất bạn có thể sẽ phân tích nó thành một "khối" tại một thời điểm, "stdout.read (1)" sẽ chỉ chặn khi không còn ký tự nào trong bộ đệm.

21

Thay vì gọi exec_command trên máy khách, hãy giữ vận chuyển và tạo kênh của riêng bạn. Các channel có thể được sử dụng để thực thi một lệnh, và bạn có thể sử dụng nó trong một tuyên bố chọn để tìm hiểu khi dữ liệu có thể được đọc:

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

Đối tượng kênh có thể được đọc từ và ghi vào, kết nối với thiết bị xuất chuẩn và stdin của lệnh từ xa. Bạn có thể nhận được stderr bằng cách gọi channel.makefile_stderr(...).

Tôi đã đặt thời gian chờ thành 0.0 giây vì giải pháp không chặn được yêu cầu. Tùy thuộc vào nhu cầu của bạn, bạn có thể muốn chặn với thời gian chờ khác không.

+0

bạn không thể chọn đối tượng stdout, vì nó thiếu thuộc tính fileno. goathens không sử dụng đối tượng kênh. – JimB

+0

Tôi đã sửa đổi và mở rộng ví dụ và thử nghiệm nó để đảm bảo nó hoạt động :). –

+0

Điều này làm việc với stderr cũng nếu bạn thay thế rl bằng xl? –

6

Chỉ cần cập nhật nhỏ cho giải pháp của Andrew Aylett. Đoạn mã sau thực sự phá vỡ vòng lặp và thoát khi quá trình bên ngoài kết thúc:

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) 
+2

Tại sao không chỉ làm 'trong khi không phải channel.exit_status_ready():'? – azmeuk

+0

Ngoài ra, hãy xem http://stackoverflow.com/questions/760978/long-running-ssh-commands-in-python-paramiko-module-and-how-to-end-them#comment64123397_766255 – azmeuk

+1

@azmeuk Cả hai giải pháp đều hơi không chính xác, bởi vì bạn không muốn ngừng nhận đầu ra ngay khi trạng thái thoát đã sẵn sàng. Bạn muốn dừng khi không có đầu ra nào được nhận VÀ trạng thái thoát đã sẵn sàng. Nếu không, bạn có thể kết thúc bỏ trước khi nhận tất cả đầu ra. – user7610

Các vấn đề liên quan