Python paramiko模块中的长时间运行的ssh命令(以及如何结束它们)
我想在远程机器上用Python的paramiko模块运行一个 tail -f logfile
命令。我到目前为止是这样尝试的:
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
一样给通道的输入发送信号? readline()
会阻塞,这样的话我就得用线程了。如果能有一种非阻塞的方法来获取输出就好了,有什么想法吗?
6 个回答
9
这是对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)
23
与其在客户端直接调用exec_command,不如先获取传输对象,然后自己创建一个通道。这个通道可以用来执行命令,你还可以在选择语句中使用它,来判断什么时候可以读取数据:
#!/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(...)
来获取错误输出。
我把超时时间设置为0.0
秒,因为这是一个非阻塞的解决方案。如果你有不同的需求,可能需要设置一个非零的超时时间来阻塞。
15
1) 如果你想的话,可以直接关闭客户端。另一边的服务器会自动结束相关的进程。
2) 如果你想以非阻塞的方式来处理这个问题,就需要直接使用通道对象。这样你可以同时监控标准输出和错误输出,方法是使用channel.recv_ready()和channel.recv_stderr_ready(),或者使用select.select。