以下代码独立等待输出和错误输出,性能良好。
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Renci.SshNet;
namespace DockerTester
{
public static class SshCommandExtensions
{
public static async Task ExecuteAsync(
this SshCommand sshCommand,
IProgress<ScriptOutputLine> progress,
CancellationToken cancellationToken)
{
var asyncResult = sshCommand.BeginExecute();
var stdoutReader = new StreamReader(sshCommand.OutputStream);
var stderrReader = new StreamReader(sshCommand.ExtendedOutputStream);
var stderrTask = CheckOutputAndReportProgressAsync(sshCommand, asyncResult, stderrReader, progress, true, cancellationToken);
var stdoutTask = CheckOutputAndReportProgressAsync(sshCommand, asyncResult, stdoutReader, progress, false, cancellationToken);
await Task.WhenAll(stderrTask, stdoutTask);
sshCommand.EndExecute(asyncResult);
}
private static async Task CheckOutputAndReportProgressAsync(
SshCommand sshCommand,
IAsyncResult asyncResult,
StreamReader streamReader,
IProgress<ScriptOutputLine> progress,
bool isError,
CancellationToken cancellationToken)
{
while (!asyncResult.IsCompleted || !streamReader.EndOfStream)
{
if (cancellationToken.IsCancellationRequested)
{
sshCommand.CancelAsync();
}
cancellationToken.ThrowIfCancellationRequested();
var stderrLine = await streamReader.ReadLineAsync();
if (!string.IsNullOrEmpty(stderrLine))
{
progress.Report(new ScriptOutputLine(
line: stderrLine,
isErrorLine: isError));
}
// wait 10 ms
await Task.Delay(10, cancellationToken);
}
}
}
public class ScriptOutputLine
{
public ScriptOutputLine(string line, bool isErrorLine)
{
Line = line;
IsErrorLine = isErrorLine;
}
public string Line { get; private set; }
public bool IsErrorLine { get; private set; }
}
}
你可以使用它:
var outputs = new Progress<ScriptOutputLine>(ReportProgress);
using (var command =
sshClient.RunCommand(
"LONG_RUNNING_COMMAND"))
{
await command.ExecuteAsync(outputs, CancellationToken.None);
await Console.Out.WriteLineAsync("Status code: " + command.ExitStatus);
}
以及报告进度的方法的示例实现:
private static void ReportProgress(ScriptOutputLine obj)
{
var color = Console.ForegroundColor;
if (obj.IsErrorLine)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(obj.Line);
Console.ForegroundColor = color;
}
Console.WriteLine(obj.Line);
}