Getting full command output from ShellStream of C# SSH.NET

T4mer picture T4mer · Dec 10, 2015 · Viewed 22.8k times · Source

Using Renci.SshNet library. I am trying to execute some commands. After executing "command 1", I am executing "command 2" which takes more time.

I am only getting the first line of the output. (reader.ReadToEnd() is not working in a proper way).

I also tried while (!reader.EndOfStream){ } with no luck.

I think it is because the delay of the response from server. When there is no response the stream read nothing and finishes.

I found a solution

String tmp;
TimeSpan timeout = new TimeSpan(0, 0, 3);
while ((tmp = s.ReadLine()) != null)
{
    Console.WriteLine(tmp);
}

But this is not professional. I need some way in which the stream ends when it ends.

using (var vclient = new SshClient("host", "username", "password"))
{
    vclient.Connect();
    using (ShellStream shell = vclient.CreateShellStream("dumb", 80, 24, 800, 600, 1024))
    {
        Console.WriteLine(SendCommand("comand 1", shell));
        Console.WriteLine(SendCommand("comand 2", shell));
        shell.Close();
    }
    vclient.Disconnect();
}

public static string SendCommand(string cmd, ShellStream sh)
{
    StreamReader reader = null;
    try
    {
        reader = new StreamReader(sh);
        StreamWriter writer = new StreamWriter(sh);
        writer.AutoFlush = true;
        writer.WriteLine(cmd);
        while (sh.Length == 0)
        {
            Thread.Sleep(500);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("exception: " + ex.ToString());
    }
    return reader.ReadToEnd();
}               

Answer

Martin Prikryl picture Martin Prikryl · Dec 11, 2015

The shell is an endless stream. There's no send command – receive output sequence. The ReadToEnd cannot know where an output of one command ends. All you can do is to read until you yourself can tell that the output ended. If you cannot tell that, you can help yourself by appending some kind of end-of-output mark like:

command 1 ; echo this-is-the-end-of-the-output

and read until you get "this-is-the-end-of-the-output" line.


Generally a "shell" channel is not an ideal solution for automation. It's intended for an interactive sessions.

You better use "exec" channel using SshClient.CreateCommand. With CreateCommand the channel closes once the command finishes. So there's clear "end of the stream", what makes the ReadToEnd() work as you expect. And SSH.NET even makes whole command output available in SshCommand.Result (which internally uses ReadToEnd()).