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?
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
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.
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.
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.Just a small update to the solution by Andrew Aylett. The following code actually breaks the loop and quits when the external process finishes: