捕获并重新显示标准输出提示:在换行符之前读取标准输出

时间:2014-07-14 19:13:14

标签: c# .net stdout

我有一个包装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?

0 个答案:

没有答案