Capture de la sortie de la console à partir d'une application .NET (C #)

130

Comment appeler une application console à partir de mon application .NET et capturer toute la sortie générée dans la console?

(N'oubliez pas que je ne veux pas enregistrer les informations d'abord dans un fichier, puis les remettre en vente car j'aimerais les recevoir en direct.)

Gripsoft
la source
Possible duplication de Process.start: comment obtenir la sortie?
Michael Freidgeim
Veuillez consulter les dates sur les deux questions et voir laquelle est "dupliquée"
Gripsoft
«Possible duplicate» est un moyen de nettoyer - pour fermer des questions similaires et en garder une avec les meilleures réponses. La date n'est pas indispensable. Voir Dois-je voter pour fermer une question en double, même si elle est beaucoup plus récente et qu'elle contient des réponses plus à jour? Si vous acceptez que cela nécessite une clarification, veuillez voter sur Ajouter un lien de clarification au commentaire automatisé "Possible duplicate"
Michael Freidgeim

Réponses:

163

Cela peut être réalisé assez facilement à l'aide de la propriété ProcessStartInfo.RedirectStandardOutput . Un exemple complet est contenu dans la documentation MSDN liée; la seule mise en garde est que vous devrez peut-être également rediriger le flux d'erreur standard pour voir toute la sortie de votre application.

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
la source
3
Si vous ne voulez pas la nouvelle ligne supplémentaire à la fin, utilisez simplement à la Console.Writeplace.
tm1
2
Il convient de noter que si vous utilisez ReadToEnd () en combinaison avec une application console qui a la capacité d'inviter l'utilisateur à entrer. Par exemple: Ecraser le fichier: O ou N? etc Ensuite, ReadToEnd peut entraîner une fuite de mémoire, car le processus ne se termine jamais en attendant l'entrée de l'utilisateur. Le moyen le plus sûr de capturer la sortie consiste à utiliser le gestionnaire d'événements process.OutputDataReceived et à laisser le processus notifier à votre application la réception de la sortie.
Baaleos
Comment capturer si au cas où le code est déployé sur azure webapp, puisque le compilateur.StartInfo.FileName = "csc.exe"; n'existe peut-être pas!
Asif Iqbal
Comment capturer si au cas où le code est déployé sur azure webapp, puisque le compilateur.StartInfo.FileName = "csc.exe"; n'existe peut-être pas!
Asif Iqbal
37

C'est une petite amélioration par rapport à la réponse acceptée de @mdb . Plus précisément, nous capturons également la sortie d'erreur du processus. De plus, nous capturons ces sorties via des événements car ReadToEnd()cela ne fonctionne pas si vous souhaitez capturer à la fois l' erreur et la sortie régulière. Il m'a fallu du temps pour que cela fonctionne car cela nécessite également des BeginxxxReadLine()appels aprèsStart() .

Manière asynchrone:

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
la source
5
Merci d'avoir cherché cela depuis des lustres!
C Bauer
3
Je vous remercie. C'est parfait.
DrFloyd5
1
Vous obtiendrez une place d'honneur dans la liste de remerciements de ma candidature.
marsh-wiggle
7

ConsoleAppLauncher est une bibliothèque open source spécialement conçue pour répondre à cette question. Il capture toute la sortie générée dans la console et fournit une interface simple pour démarrer et fermer l'application console.

L'événement ConsoleOutput est déclenché chaque fois qu'une nouvelle ligne est écrite par la console dans la sortie standard / d'erreur. Les lignes sont mises en file d'attente et sont garanties de suivre l'ordre de sortie.

Également disponible en tant que package NuGet .

Exemple d'appel pour obtenir la sortie complète de la console:

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

Échantillon avec commentaires en direct:

// 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
la source
2

J'ai ajouté un certain nombre de méthodes d'aide à la plate-forme O2 (projet Open Source) qui vous permettent de programmer facilement une interaction avec un autre processus via la sortie et l'entrée de la console (voir http://code.google.com/p/o2platform/ source / parcourir / trunk / O2_Scripts / APIs / Windows / CmdExe / CmdExeAPI.cs )

L'API qui permet de visualiser la sortie de la console du processus en cours (dans un contrôle existant ou une fenêtre contextuelle) peut également vous être utile. Voir ce billet de blog pour plus de détails: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (ce blog contient également des détails sur la façon de consommer la sortie console des nouveaux processus)

Dinis Cruz
la source
Depuis lors, j'ai ajouté plus de support pour l'utilisation de ConsoleOut (dans ce cas, si vous démarrez vous-même le processus .NET). Jetez un oeil à: Comment utiliser la sortie de la console dans le C # REPL , Ajout de 'Console Out' à VisualStudio IDE en tant que fenêtre native , Affichage des messages 'Console Out' créés dans UserControls
Dinis Cruz
2

J'ai fait une version réactive qui accepte les rappels pour stdOut et StdErr.
onStdOutet onStdErrsont appelés de manière asynchrone,
dès que les données arrivent (avant la fin du processus).

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


Exemple d'utilisation

Ce qui suit fonctionnera executableavec argset imprimera

  • stdOut en blanc
  • stdErr en rouge

à la console.

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

Depuis 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
la source
1

Ajouté process.StartInfo.**CreateNoWindow** = true;et 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;
        }
    }
}
Sergueï Zinovyev
la source
Lorsque vous l'utilisez, StandardOutput.ReadToEnd()il ne reviendra pas à l'instruction suivante avant la fin de l'application. donc votre timeout dans WaitForExit (timeoutMilliseconds) ne fonctionne pas! (votre code va se bloquer!)
S.Serpooshan