Захват вывода консоли из приложения .NET (C #)


130

Как мне вызвать консольное приложение из моего .NET-приложения и записать весь вывод, сгенерированный в консоли?

(Помните, я не хочу сначала сохранять информацию в файле, а затем повторно добавлять ее, поскольку я бы хотел получить ее как живую.)



Пожалуйста, посмотрите даты по обоим вопросам и посмотрите, какой из них "дублирует"
Gripsoft

«Возможный дубликат» - это способ навести порядок - закрыть похожие вопросы и оставить один с лучшими ответами. Дата не важна. См. Раздел « Должен ли я голосовать за закрытие повторяющегося вопроса, даже если он намного новее и содержит более свежие ответы?» Если вы согласны с тем, что это требует разъяснения, пожалуйста, проголосуйте за добавление уточняющей ссылки к автоматическому комментарию «Возможный дубликат»
Майкл

Ответы:


163

Этого довольно легко добиться с помощью свойства ProcessStartInfo.RedirectStandardOutput . Полный образец содержится в связанной документации MSDN; единственное предостережение: вам, возможно, придется перенаправить и стандартный поток ошибок, чтобы увидеть весь вывод вашего приложения.

Process compiler = new Process();
compiler.StartInfo.FileName = "csc.exe";
compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();    

Console.WriteLine(compiler.StandardOutput.ReadToEnd());

compiler.WaitForExit();

3
Если вам не нужна дополнительная новая строка в конце, просто используйте Console.Writeвместо нее.
tm1 08

2
Следует отметить, что если вы используете ReadToEnd () в сочетании с консольным приложением, которое имеет возможность запрашивать у пользователя ввод. Например: перезаписать файл: ДА или НЕТ? и т.д. Тогда ReadToEnd может привести к утечке памяти, поскольку процесс никогда не завершается, ожидая ввода данных пользователем. Более безопасный способ захвата вывода - использовать обработчик событий process.OutputDataReceived и позволить процессу уведомлять ваше приложение о получении вывода.
Baaleos

Как зафиксировать, если в случае развертывания кода в azure webapp, поскольку compiler.StartInfo.FileName = "csc.exe"; может не существует!
Асиф Икбал,

Как зафиксировать, если в случае развертывания кода в azure webapp, поскольку compiler.StartInfo.FileName = "csc.exe"; может не существует!
Асиф Икбал,

37

Это небольшое улучшение по сравнению с принятым ответом от @mdb . В частности, мы также фиксируем вывод ошибок процесса. Кроме того, мы фиксируем эти выходные данные через события, потому что ReadToEnd()это не работает, если вы хотите фиксировать как ошибки, так и обычные выходные данные. Мне потребовалось время, чтобы выполнить эту работу, потому что на самом деле также требуются BeginxxxReadLine()звонки после Start().

Асинхронный способ:

using System.Diagnostics;

Process process = new Process();

void LaunchProcess()
{
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
    process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
    process.Exited += new System.EventHandler(process_Exited);

    process.StartInfo.FileName = "some.exe";
    process.StartInfo.Arguments = "param1 param2";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;

    process.Start();
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();          

    //below line is optional if we want a blocking call
    //process.WaitForExit();
}

void process_Exited(object sender, EventArgs e)
{
    Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString()));
}

void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}

void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}

5
Спасибо, давно искал это!
C Bauer

3
Спасибо. Это потрясающе.
DrFloyd5

1
Вы получите почетное место в списке благодарностей моей заявки.
marsh-wiggle


7

ConsoleAppLauncher - это библиотека с открытым исходным кодом, созданная специально для ответа на этот вопрос. Он фиксирует весь вывод, сгенерированный в консоли, и предоставляет простой интерфейс для запуска и закрытия консольного приложения.

Событие ConsoleOutput запускается каждый раз, когда консоль записывает новую строку в стандартный вывод или вывод ошибок. Строки ставятся в очередь и гарантированно следуют порядку вывода.

Также доступен как пакет NuGet .

Пример вызова для получения полного вывода на консоль:

// Run simplest shell command and return its output.
public static string GetWindowsVersion()
{
    return ConsoleApp.Run("cmd", "/c ver").Output.Trim();
}

Образец с обратной связью:

// Run ping.exe asynchronously and return roundtrip times back to the caller in a callback
public static void PingUrl(string url, Action<string> replyHandler)
{
    var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled);
    var app = new ConsoleApp("ping", url);
    app.ConsoleOutput += (o, args) =>
    {
        var match = regex.Match(args.Line);
        if (match.Success)
        {
            var roundtripTime = match.Groups["time"].Value;
            replyHandler(roundtripTime);
        }
    };
    app.Run();
}

2

Я добавил несколько вспомогательных методов в платформу O2 (проект с открытым исходным кодом), которые позволяют легко создавать сценарии взаимодействия с другим процессом через вывод и ввод консоли (см. Http://code.google.com/p/o2platform/ источник / просмотр / транк / O2_Scripts / API / Windows / CmdExe / CmdExeAPI.cs )

Также вам может быть полезен API, который позволяет просматривать вывод на консоль текущего процесса (в существующем элементе управления или всплывающем окне). Дополнительную информацию см. В этом сообщении в блоге: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (этот блог также содержит сведения о том, как потреблять консольный вывод новых процессов)


С тех пор я добавил дополнительную поддержку для использования ConsoleOut (в этом случае, если вы запустите процесс .NET самостоятельно). Взгляните на: Как использовать вывод консоли в C # REPL , Добавление «Console Out» в VisualStudio IDE в качестве собственного окна , Просмотр сообщений «Console Out», созданных внутри UserControls
Динис Круз,

2

Я сделал реактивную версию, которая принимает обратные вызовы для stdOut и StdErr.
onStdOutи onStdErrвызываются асинхронно,
как только данные поступают (до завершения процесса).

public static Int32 RunProcess(String path,
                               String args,
                       Action<String> onStdOut = null,
                       Action<String> onStdErr = null)
    {
        var readStdOut = onStdOut != null;
        var readStdErr = onStdErr != null;

        var process = new Process
        {
            StartInfo =
            {
                FileName = path,
                Arguments = args,
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardOutput = readStdOut,
                RedirectStandardError = readStdErr,
            }
        };

        process.Start();

        if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut));
        if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr));

        process.WaitForExit();

        return process.ExitCode;
    }

    private static void ReadStream(TextReader textReader, Action<String> callback)
    {
        while (true)
        {
            var line = textReader.ReadLine();
            if (line == null)
                break;

            callback(line);
        }
    }


Пример использования

Следующее будет работать executableс argsи печатать

  • stdOut в белом
  • stdErr красным

к консоли.

RunProcess(
    executable,
    args,
    s => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(s); },
    s => { Console.ForegroundColor = ConsoleColor.Red;   Console.WriteLine(s); } 
);

1

Из PythonTR - Python Programcıları Derneği, e-kitap, örnek :

Process p = new Process();   // Create new object
p.StartInfo.UseShellExecute = false;  // Do not use shell
p.StartInfo.RedirectStandardOutput = true;   // Redirect output
p.StartInfo.FileName = "c:\\python26\\python.exe";   // Path of our Python compiler
p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py";   // Path of the .py to be executed

1

Добавлены process.StartInfo.**CreateNoWindow** = true;и timeout.

private static void CaptureConsoleAppOutput(string exeName, string arguments, int timeoutMilliseconds, out int exitCode, out string output)
{
    using (Process process = new Process())
    {
        process.StartInfo.FileName = exeName;
        process.StartInfo.Arguments = arguments;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.CreateNoWindow = true;
        process.Start();

        output = process.StandardOutput.ReadToEnd();

        bool exited = process.WaitForExit(timeoutMilliseconds);
        if (exited)
        {
            exitCode = process.ExitCode;
        }
        else
        {
            exitCode = -1;
        }
    }
}

Когда вы используете, StandardOutput.ReadToEnd()он не вернется к следующему оператору до конца приложения. так что ваш тайм-аут в WaitForExit (timeoutMilliseconds) не работает! (ваш код
зависнет
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.