Erfassen der Konsolenausgabe aus einer .NET-Anwendung (C #)

129

Wie rufe ich eine Konsolenanwendung aus meiner .NET-Anwendung auf und erfasse alle in der Konsole generierten Ausgaben?

(Denken Sie daran, ich möchte die Informationen nicht zuerst in einer Datei speichern und dann erneut auflisten, da ich sie gerne live erhalten würde.)

Gripsoft
quelle
Mögliches Duplikat von Process.start: Wie erhalte ich die Ausgabe?
Michael Freidgeim
Bitte sehen Sie die Daten auf beiden Fragen und sehen Sie, welche "doppelt" ist
Gripsoft
"Mögliches Duplikat" ist ein Weg zur Bereinigung - um ähnliche Fragen zu schließen und eine mit den besten Antworten zu behalten. Das Datum ist nicht wesentlich. Siehe Soll ich abstimmen, um eine doppelte Frage zu schließen, obwohl sie viel neuer ist und aktuellere Antworten enthält? Wenn Sie damit einverstanden sind, dass eine Klärung erforderlich ist, stimmen Sie bitte über den Link "Klärung hinzufügen" zum automatisierten Kommentar "Mögliches Duplikat" ab
Michael Freidgeim,

Antworten:

163

Dies kann ganz einfach mit der ProcessStartInfo.RedirectStandardOutput- Eigenschaft erreicht werden. Ein vollständiges Beispiel ist in der verknüpften MSDN-Dokumentation enthalten. Die einzige Einschränkung besteht darin, dass Sie möglicherweise auch den Standardfehlerstrom umleiten müssen, um alle Ausgaben Ihrer Anwendung anzuzeigen.

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();
mdb
quelle
3
Wenn Sie die zusätzliche neue Zeile am Ende nicht möchten, verwenden Sie Console.Writestattdessen einfach .
tm1
2
Es ist zu beachten, dass bei Verwendung von ReadToEnd () in Kombination mit einer Konsolenanwendung der Benutzer zur Eingabe aufgefordert werden kann. Beispiel: Datei überschreiben: J oder N? usw. Dann kann ReadToEnd zu einem Speicherverlust führen, da der Prozess niemals beendet wird, während auf Benutzereingaben gewartet wird. Die sicherere Methode zum Erfassen der Ausgabe besteht darin, den Ereignishandler process.OutputDataReceived zu verwenden und den Prozess Ihre Anwendung über die empfangene Ausgabe benachrichtigen zu lassen.
Baaleos
Wie wird erfasst, ob der Code für die Azure-Webanwendung bereitgestellt wird, da der Compiler.StartInfo.FileName = "csc.exe"; existiert möglicherweise nicht!
Asif Iqbal
Wie wird erfasst, ob der Code für die Azure-Webanwendung bereitgestellt wird, da der Compiler.StartInfo.FileName = "csc.exe"; existiert möglicherweise nicht!
Asif Iqbal
37

Dies ist eine kleine Verbesserung gegenüber der akzeptierten Antwort von @mdb . Insbesondere erfassen wir auch die Fehlerausgabe des Prozesses. Darüber hinaus erfassen wir diese Ausgaben über Ereignisse, da ReadToEnd()dies nicht funktioniert, wenn Sie sowohl Fehler als auch reguläre Ausgaben erfassen möchten . Ich habe eine Weile gebraucht, um diese Arbeit zu machen, da es tatsächlich auch BeginxxxReadLine()Anrufe danach erfordert Start().

Asynchroner Weg:

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");
}
Shital Shah
quelle
5
Danke, ich habe lange danach gesucht!
C Bauer
3
Danke dir. Dies ist perfekt.
DrFloyd5
Sie erhalten einen Ehrenplatz in der Dankesliste meiner Bewerbung.
Marsh-Wiggle
7

ConsoleAppLauncher ist eine Open Source-Bibliothek, die speziell zur Beantwortung dieser Frage entwickelt wurde. Es erfasst alle in der Konsole generierten Ausgaben und bietet eine einfache Oberfläche zum Starten und Schließen der Konsolenanwendung.

Das ConsoleOutput-Ereignis wird jedes Mal ausgelöst, wenn eine neue Zeile von der Konsole in die Standard- / Fehlerausgabe geschrieben wird. Die Zeilen werden in die Warteschlange gestellt und folgen garantiert der Ausgabereihenfolge.

Auch als NuGet-Paket erhältlich .

Beispielaufruf, um die vollständige Konsolenausgabe zu erhalten:

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

Beispiel mit Live-Feedback:

// 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();
}
SlavaGu
quelle
2

Ich habe der O2-Plattform (Open Source-Projekt) eine Reihe von Hilfsmethoden hinzugefügt, mit denen Sie auf einfache Weise eine Interaktion mit einem anderen Prozess über die Konsolenausgabe und -eingabe per Skript ausführen können (siehe http://code.google.com/p/o2platform/). source / browse / trunk / O2_Scripts / APIs / Windows / CmdExe / CmdExeAPI.cs )

Für Sie könnte auch die API nützlich sein, mit der die Konsolenausgabe des aktuellen Prozesses angezeigt werden kann (in einem vorhandenen Steuerelement oder Popup-Fenster). Weitere Informationen finden Sie in diesem Blog-Beitrag: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (dieses Blog enthält auch Details zum Verbrauch die Konsolenausgabe neuer Prozesse)

Dinis Cruz
quelle
Seitdem habe ich mehr Unterstützung für die Verwendung von ConsoleOut hinzugefügt (in diesem Fall, wenn Sie den .NET-Prozess selbst starten). Schauen Sie sich Folgendes an: Verwendung der Konsolenausgabe in C # REPL , Hinzufügen von 'Console Out' zu VisualStudio IDE als natives Fenster , Anzeigen von 'Console
Dinis Cruz
2

Ich habe eine reaktive Version erstellt, die Rückrufe für stdOut und StdErr akzeptiert.
onStdOutund onStdErrwerden asynchron aufgerufen,
sobald Daten eintreffen (bevor der Prozess beendet wird).

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);
        }
    }


Anwendungsbeispiel

Folgendes wird executablemit ausgeführt argsund gedruckt

  • stdOut in weiß
  • stdErr in rot

zur Konsole.

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

Von 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
livetogogo
quelle
1

Hinzugefügt process.StartInfo.**CreateNoWindow** = true;und 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;
        }
    }
}
Sergei Zinovyev
quelle
Wenn Sie es verwenden StandardOutput.ReadToEnd(), wird es erst am Ende der App zur nächsten Anweisung zurückkehren. Ihr Timeout in WaitForExit (timeoutMilliseconds) funktioniert also nicht! (Ihr Code wird hängen!)
S.Serpooshan