Tailing a file as its being written

Mar 14, 2011 at 6:50 PM

Hey all,

I've been writing a custom log viewer and the need arose to be able to view the live logs (done with the tail command in unix).  My logviewer currently opens the backup log files and applies some magic to them to make them much more human readable, including some color and search/parse options.  Anywho, I've been looking into using one of these SSH libraries to accomplish this task, but I have zero experiance in this type of programming and really only know how to use your basic TelNet client.  Would this task be possible given this library? (Again, the file will not be edited at all, just copied into .NET where I color code it and parse it) Thanks!

Mar 14, 2011 at 7:05 PM

The simple answer is YES.


How would you do it is another question.


All this library does is allows you to remotly execute any shell comamnds on remote server. So assuming you have right permission to access the file you can do one of the following:

1. Execute "cat <full file nane> command, which will return content of the file into output stream.

2. You can download the remote file using SFTP and read the stream in your application so you dont relaly need to save it into the file on your disk, unless you really want to.


There might be other scenarios, but those two are coming into my mind right now.

Mar 14, 2011 at 7:27 PM

Cool, well, since its a live file (always being written too) downloading might not be the best option because once I download it, it will be immediatly out of date.... could I use the unix tail command and stream in the results?

Mar 14, 2011 at 10:55 PM

yes, you can execute any single unix command with this library. 

so yes, you can run "tail ...." and will get back results as if you were to run it on unix.


Hope it helps,


Mar 15, 2011 at 1:24 PM
Edited Mar 15, 2011 at 1:41 PM

Awesome thanks!  Also, is there a trick to get your help file working (in Renci.SshClient\Documentation\Content\Help\SshClient.chm)?  When I open it, it correctly shows the contents on the left side but no matter what you click on theres no content.

EDIT: Nevermind, was a problem with my security settings

Mar 29, 2011 at 1:56 PM

Just in case anyone searches the discussions about the .chm file. It needs to be unblocked on Vista:



Apr 6, 2011 at 2:16 PM

Hey Oleg,

I have a question for you with implementing tail... I know that your library sends the command, it runs unix side and then once its done (maybe I have this part wrong) returns the results to the program... but unix functions like tail -f (follow the file) dont have an "end", the only way out of tail -f is to ctrl-c to kill the previous command.  So in these causes will the SSH library be stuck waiting for a reply that will never come, or is there another way to do this?

Thanks man!

Apr 6, 2011 at 2:24 PM



I am leaving for business trip so will be away for a while to test this solution,

but you raising interesting scenario which I didn't think of.


One think I would like you to try is to execute the command in async way and instead of readin the Result property try to read from output stream,

I dont remember the exact syntax but this is an idea.


Let me know if you can make it work and if not I will look at it when I am back.


One thing I did think about is to provide a way to cancel the command that being executed but never got to it just yet.


Hope it helps.



Apr 6, 2011 at 4:19 PM

Thanks Oleg, Ill try out the output stream.

In reguards to canceling a command, on my unix box (in unix) its ctrl-c to cancel out a running command, so would it be possible to have a flag in the loop for the output stream that checks if the user wants to cancel, and if they do does some kind of

var cmd = client.RunCommand(Whatever string equates to sending a ctrl-c);

unixResults = cmd.Result;



Though Im not sure exactly what the string in RunCommand should be...

Thanks, have a great business trip!

Apr 12, 2011 at 6:43 PM

Hey Oleg,

I was wondering if you were able to put any more thought into my tail issue.... unfortunatly Ive been pretty busy at work and havent got to try the output stream idea (plus the unix admins dont want me leaving a bunch of potenitally open connections on thier servers)  Do you still think thats the best way to go?

Apr 12, 2011 at 6:50 PM

sorry, I didnt get to it yet as I am trying to add more encryptions into the library right now and dont want mess up the code in the middle,

but I will try what I suggested as soon as I done with it and check something.




Apr 12, 2011 at 6:52 PM

No worries, I totally understand that... I too hate the distractions right when you're on a roll with something haha

Apr 14, 2011 at 5:42 PM



So I did a little test and I managed to execute "tail -f" command and see results on my screen but unfortunatly is not supported by current version and will require some changes.

So I will pospote it for later but if you can, please open it as a bug or feature request so I could remeber to get back to it later, when I have more time.




Apr 14, 2011 at 6:17 PM
Edited Apr 14, 2011 at 6:29 PM

Thank you so much, thats awesome!  Itll be able to cancel the command and close the connection too right?

Edit: Issue is created... item #666, creepy haha

Apr 14, 2011 at 7:19 PM

Yea, you should be able to cancel the command, I want to make it so you could pass cancel code if possible, but if not, I`ll just brutally will close the channel and this will cause command to exit

but need to see whats the best approach would be here.


yea, bug 666...ouch, hope could fix it fast then :):)

Apr 15, 2011 at 5:56 PM

Awesome, sounds good! Im getting a lot a requests for the ability to tail a file so I cant wait! 

Thanks again for the great work!

Apr 25, 2011 at 9:25 PM

Hey man, just wondering where ya stand with this, keep up the good work!

Apr 28, 2011 at 2:20 PM


sorry but recently I been busy with few other projects that I have to work on so I wasn't be able to find time to work on it.

All I manage to do right now is to reply to posts here.


I will get to it as soon as I can get some free time.

The reason I can't do it as quick fix is because it can affect existing functionality, so I would need to be careful not to break anything that works right now, thats why I dont want to attack it in just couple hours :(


Sorry for the delay,



Apr 28, 2011 at 6:00 PM

No worries man, just checkin up, thats all.  As always, thanks for a great product!

May 5, 2011 at 6:27 PM
Edited May 5, 2011 at 6:28 PM

Out of curiousty did any of those new source code uploads include tail stuff you were talking about a few posts up? If not, no worries!

May 5, 2011 at 6:35 PM

actually about to start working on it right now,

looking for tail examples now that I can test against :):)

May 5, 2011 at 6:50 PM


As I start digging into I think I might find an alternative solution which you can try right now:

            using (var ssh = new SshClient(connectionInfo))
                var cmd = ssh.CreateCommand("tail -f /var/log/auth.log");

                var asynch = cmd.BeginExecute(null, null);
                while (!asynch.IsCompleted)
                    var output = Encoding.ASCII.GetString(cmd.OutputStream.ToArray());

The problem with that is that it keep printing the same output from previous call, so I need to find a way either to eliminate previous data so it doesn't read same data again, providing a different stream to output data into or something else, which I didnt think about it yet.

Will keep you updated, but just wanted to let you know what I have so far.

May 5, 2011 at 8:05 PM
Edited May 5, 2011 at 8:08 PM

Awesome man! Thanks!

As far as testing goes, at least in my situation is a live log file that is being written to and tailing on to the end of it

Jan 22, 2014 at 7:30 AM
Any update on the problem with the complete reprint of the output?
Jan 22, 2014 at 6:16 PM
Edited Jan 22, 2014 at 6:17 PM
So here's how I did it, it works-ish, but sometimes randomly disconnects or stops tailing. Let me know if you have any questions.
PasswordConnectionInfo connectionInfo = new PasswordConnectionInfo(LogData.IpAddress, LogData.Username, LogData.Password);

using (var ssh = new SshClient(connectionInfo))
    string reply = String.Empty;

    using (var shellStream = ssh.CreateShellStream("dumb", 0, 0, 0, 0, BUFFERSIZE)) // BUFFERSIZE Set to 1024 for me
        // Wait for prompt
        reply = shellStream.Expect(new Regex(LogData.ServerName.ToLower() + @":.*>"), new TimeSpan(0, 0, 10));
        shellStream.WriteLine(command);  // command is the tail command, ie "tail -f filename"
        // Keep reading until a cancel request is given
        while (!WorkerThread.CancellationPending)
            string result = shellStream.ReadLine(new TimeSpan(0, 0, 10));
            if (!String.IsNullOrEmpty(result) && !result.Contains(LogData.ServerName.ToLower()))