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() 会阻塞,如果我有一个非阻塞的获取输出的方法,我可以避免线程 - 有什么想法吗?
I want to run a tail -f logfile
command on a remote machine using python's paramiko module. I've been attempting it so far in the following fashion:
interface = paramiko.SSHClient()
#snip the connection setup portion
stdin, stdout, stderr = interface.exec_command("tail -f logfile")
#snip into threaded loop
print stdout.readline()
I'd like the command to run as long as necessary, but I have 2 problems:
- How do I stop this cleanly? I thought of making a Channel and then using the
shutdown()
command on the channel when I'm through with it- but that seems messy. Is it possible to do something like sentCtrl-C
to the channel's stdin? readline()
blocks, and I could avoid threads if I had a non-blocking method of getting output- any thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
不要在客户端调用 exec_command,而是掌握传输并生成您自己的通道。 频道 可用于执行命令,并且您可以在 select 语句中使用它来确定何时可以读取数据:
可以读取和写入通道对象,与远程命令的 stdout 和 stdin 连接。 您可以通过调用channel.makefile_stderr(...)来获取stderr。
我已将超时设置为
0.0
秒,因为请求了非阻塞解决方案。 根据您的需要,您可能希望使用非零超时进行阻止。Instead of calling exec_command on the client, get hold of the transport and generate your own channel. The channel can be used to execute a command, and you can use it in a select statement to find out when data can be read:
The channel object can be read from and written to, connecting with stdout and stdin of the remote command. You can get at stderr by calling
channel.makefile_stderr(...)
.I've set the timeout to
0.0
seconds because a non-blocking solution was requested. Depending on your needs, you might want to block with a non-zero timeout.1)如果您愿意,您可以关闭客户端。 另一端的服务器将杀死尾部进程。
2)如果您需要以非阻塞方式执行此操作,则必须直接使用通道对象。 然后,您可以使用channel.recv_ready()和channel.recv_stderr_ready()来监视stdout和stderr,或者使用select.select。
1) You can just close the client if you wish. The server on the other end will kill the tail process.
2) If you need to do this in a non-blocking way, you will have to use the channel object directly. You can then watch for both stdout and stderr with channel.recv_ready() and channel.recv_stderr_ready(), or use select.select.
只是对 Andrew Aylett 的解决方案进行了一个小更新。 以下代码实际上打破了循环并在外部进程完成时退出:
Just a small update to the solution by Andrew Aylett. The following code actually breaks the loop and quits when the external process finishes:
要关闭该进程,只需运行:
就非阻塞而言,您无法获得非阻塞读取。 最好的方法是一次解析一个“块”,“stdout.read(1)”仅在缓冲区中没有剩余字符时才会阻塞。
To close the process simply run:
In terms of nonblocking, you can't get a non-blocking read. The best you would be able to to would be to parse over it one "block" at a time, "stdout.read(1)" will only block when there are no characters left in the buffer.
仅供参考,有一个解决方案可以使用channel.get_pty() 来执行此操作。 有关更多详细信息,请查看:https://stackoverflow.com/a/11190727/1480181
Just for information, there is a solution to do this using channel.get_pty(). Fore more details have a look at: https://stackoverflow.com/a/11190727/1480181
我解决这个问题的方法是使用上下文管理器。 这将确保我的长时间运行的命令被中止。 关键逻辑是包装以模仿 SSHClient.exec_command,但捕获创建的通道并使用计时器,如果命令运行时间过长,该计时器将关闭该通道。
现在使用代码非常简单,第一个示例将抛出
TimeoutError
此代码将正常工作(除非主机处于疯狂的负载之下!)
The way I've solved this is with a context manager. This will make sure my long running commands are aborted. The key logic is to wrap to mimic SSHClient.exec_command but capture the created channel and use a
Timer
that will close that channel if the command runs for too long.To use the code it's pretty simple now, the first example will throw a
TimeoutError
This code will work fine (unless the host is under insane load!)