我有一个包装Mercurial的PowerShell库。它将Mercurial的标准输出转换为对象,并返回这些对象以代替Mercurial的常规输出。我们有一些使用此库的面向用户的脚本。 Mercurial的一个操作可能有时需要身份验证,Mercurial会通过stdout提示输入用户名,例如
> hg push
pushing to repository https://example.com/hg
user:
我用.NET的System.Diagnostics.Process
对象调用Mercurial:
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace CaptureStdOutButShowPrompt
{
class Program
{
private static object _lock = new object();
static void Main(string[] args)
{
var arguments = string.Format("push https://example.com/hg");
var p = new Process
{
StartInfo =
new ProcessStartInfo
{
FileName = "hg.exe",
Arguments = arguments,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
}
};
WriteDebug("{0} {1}", p.StartInfo.FileName, p.StartInfo.Arguments);
string error = null;
p.Start();
var errThread = new Thread(() => ProcessErrorCharacters(p.StandardError));
errThread.Start();
var outputThread = new Thread(() => ProcessOutputCharacters(p.StandardOutput));
outputThread.Start();
var result = p.WaitForExit(MercurialTimeoutSeconds * 1000);
if (!result)
{
WriteDebug("Mercurial failed to finish in {0} seconds.", MercurialTimeoutSeconds);
p.Kill();
}
else
{
WriteDebug("Exit code: {0}", p.ExitCode);
}
outputThread.Join();
errThread.Join();
p.Close();
Console.ReadLine();
}
private static void ProcessOutputCharacters(StreamReader streamReader)
{
var line = new StringBuilder();
do
{
lock (_lock)
{
int outputCharInt = streamReader.Read();
if (outputCharInt == -1)
{
break;
}
char outputChar = (char)outputCharInt;
Console.Write(outputChar);
line.Append(outputChar);
if (outputChar == '\n')
{
//.Console.Write(line.ToString());
line = new StringBuilder();
}
else if (line.ToString() == "user:")
{
Console.Write(line.ToString());
var username = Console.ReadLine();
}
}
} while (true);
}
private static void ProcessErrorCharacters(StreamReader streamReader)
{
do
{
lock (_lock)
{
int outputCharInt = streamReader.Read();
if (outputCharInt == -1)
{
break;
}
char outputChar = (char) outputCharInt;
Console.Error.Write(outputChar);
}
} while (true);
}
public static int MercurialTimeoutSeconds = 60;
private static void WriteDebug(string message, params object[] args)
{
Console.WriteLine(string.Format(message, args));
}
}
}
正如你所看到的,我正在尝试逐个字符地抓取stdout,但似乎.NET不允许我抓取字符,直到进程写入换行符(\n
)。 / p>
无论如何都要在不等待换行符的情况下从进程中获取stdout?