2009-04-17 52 views
21

tail -f logfileコマンドを、pythonのparamikoモジュールを使用してリモートマシン上で実行したいとします。私は、次の方法で、これまでにそれをしようとしてきた: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というような送信を行うことはできますか?
  2. readline()ブロックをブロックすることができます。出力を取得するノンブロッキングの方法があれば、スレッドを避けることができます。
+0

SSHClient()はすでにスレッドを内部的に使用しています。 – joeforker

答えて

14

1)ご希望の場合は、クライアントを閉じることができます。もう一方の端にあるサーバーは、テールプロセスを停止します。

2)これをノンブロッキングで行う必要がある場合は、チャネルオブジェクトを直接使用する必要があります。次に、channel.recv_ready()およびchannel.recv_stderr_ready()を使用してstdoutとstderrの両方を監視するか、select.selectを使用します。

+1

私はパーティーに遅れていますが、それ自体は非exec_commandではありません。 – zengr

+1

あなたは正しいですが、質問は 'readline()'について質問します。 – Dan

+1

一部の新しいサーバーでは、クライアントを終了してもプロセスが強制終了されません。クライアントを終了した後にプロセスをクリーンアップするには、 'exec_command()'に 'get_pty = True'を設定する必要があります。 – nlsun

0

単に実行するプロセスを閉じるには:ノンブロッキングの面では

interface.close() 

を、あなたはノンブロッキングの読み取りを取得することはできません。一度に1つの "ブロック"を解析すると、バッファに文字が残っていないと "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) 

チャネルオブジェクトから読み書きすることができ、標準出力と接続し、リモートコマンドのstdin。 channel.makefile_stderr(...)を呼び出すことで、stderrにアクセスできます。

ノンブロッキングソリューションが要求されたため、タイムアウトを0.0秒に設定しました。必要に応じて、ゼロ以外のタイムアウトでブロックすることができます。

+0

fileno属性がないため、stdoutオブジェクトでは選択できません。 goathensはチャネルオブジェクトを使用していません。 – JimB

+0

私はこの例を変更して拡張し、それが動作することを確認するためにテストしました:)。 –

+0

rlをxlに置き換えた場合でも、これはstderrで動作しますか? –

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

なぜ、 'channel.exit_status_ready():'はしないのですか? – azmeuk

+0

また、http://stackoverflow.com/questions/760978/long-running-ssh-commands-in-python-paramiko-module-and-how-to-end-them#comment64123397_766255 – azmeuk

+1

@azmeuk間違っています。なぜなら、終了ステータスの準備ができたらすぐに出力の受信を停止したくないからです。受信する出力がなく、終了ステータスが準備完了のときに停止したいとします。そうしないと、すべての出力を受け取る前に終了することがあります。 – user7610

関連する問題