Process.start: how to get the output?

359,153

Solution 1

When you create your Process object set StartInfo appropriately:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

then start the process and read from it:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}

You can use int.Parse() or int.TryParse() to convert the strings to numeric values. You may have to do some string manipulation first if there are invalid numeric characters in the strings you read.

Solution 2

You can process your output synchronously or asynchronously.

1. Synchronous example

static void runCommand()
{
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.Start();
    //* Read the output (or the error)
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    string err = process.StandardError.ReadToEnd();
    Console.WriteLine(err);
    process.WaitForExit();
}

Note that it's better to process both output and errors: they must be handled separately.

(*) For some commands (here StartInfo.Arguments) you must add the /c directive, otherwise the process freezes in the WaitForExit().

2. Asynchronous example

static void runCommand() 
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set your output and error (asynchronous) handlers
    process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process and handlers
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

If you don't need to do complicate operations with the output, you can bypass the OutputHandler method, just adding the handlers directly inline:

//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);

Solution 3

Alright, for anyone who wants both Errors and Outputs read, but gets deadlocks with any of the solutions, provided in other answers (like me), here is a solution that I built after reading MSDN explanation for StandardOutput property.

Answer is based on T30's code:

static void runCommand()
{
    //* Create your Process
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Set ONLY ONE handler here.
    process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutputHandler);
    //* Start process
    process.Start();
    //* Read one element asynchronously
    process.BeginErrorReadLine();
    //* Read the other one synchronously
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process.WaitForExit();
}

static void ErrorOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

Solution 4

The standard .NET way of doing this is to read from the Process' StandardOutput stream. There is an example in the linked MSDN docs. Similar, you can read from StandardError, and write to StandardInput.

Solution 5

  1. It is possible to get the command line shell output of a process as described here : http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. This depends on mencoder. If it ouputs this status on the command line then yes :)

Share:
359,153
stighy
Author by

stighy

Updated on July 08, 2022

Comments

  • stighy
    stighy almost 2 years

    I would like to run an external command line program from my Mono/.NET app. For example, I would like to run mencoder. Is it possible:

    1. To get the command line shell output, and write it on my text box?
    2. To get the numerical value to show a progress bar with time elapsed?
  • codea
    codea over 10 years
    I was wondering how you could deal with StandardError ?. BTW I really like this code snippet ! nice and clean.
  • codea
    codea over 10 years
    Thanks,But I think I was not clear: Should I add another loop to do so ?
  • Ferruccio
    Ferruccio over 10 years
    @codea - I see. You can create one loop that terminates when both streams reach EOF. That can get a little complicated because one stream will inevitably hit EOF first and you don't want to read from it anymore. You could also use two loops in two different threads.
  • Gusdor
    Gusdor over 10 years
    is it more robust to read until the process itself terminates, rather than waiting for end of streams?
  • Ferruccio
    Ferruccio over 10 years
    @Gusdor - I don't think so. When the process terminates, its streams will automatically be closed. Also, a process may close its streams long before it terminates.
  • Richard Barker
    Richard Barker over 8 years
    gotta love async! I was able to use this code (with a little transcribing) in VB.net
  • T30
    T30 about 7 years
    Thanks for adding this. Can I ask what command you were using?
  • cubrman
    cubrman about 7 years
    I am developing an app in c# that is designed to launch a mysqldump.exe, show the user every single message the app generates, wait for it to finish and then perform some more tasks. I can't understand what kind of command you are talking about? This entire question is about launching a process from c#.
  • Andrew Hill
    Andrew Hill almost 7 years
    note 'string output = process.StandardOutput.ReadToEnd();' may produce a large string if there is many lines of output; the async example, and the answer from Ferruccio both process the output line by line.
  • S.Serpooshan
    S.Serpooshan over 6 years
    Note: your first (synchronous) approach is not correct! You should NOT read both StandardOutput and StandardError synchronously! it will cause dead-locks. atleast one of them must be async.
  • Tom
    Tom over 6 years
    Process.WaitForExit() is thread blocking, thus synchronous. Not the point of the answer, but I thought I might add this. Add process.EnableRaisingEvents = true and make use of the Exited event to be fully asynchronous.
  • ovi
    ovi about 6 years
    if you use two separate handlers you will not get deadlocks
  • ovi
    ovi about 6 years
    also in you example, you read the process.StandardOutput only once... right after you start it, but one would want to read it continuously while the process is running, no?
  • Anirudha Gupta
    Anirudha Gupta almost 6 years
    I am trying to use this code on Ffmpeg, any help, stuck in find out the processes work is completed.
  • Ini
    Ini over 4 years
    Is it not possible to directly redirect? I use all colorization of the sass output?
  • Samuel
    Samuel over 4 years
    You are missing a dispose.
  • ygoe
    ygoe over 3 years
    @S.Serpooshan Can you explain this? I wouldn't know why that should be the case. To T30: The above async code isn't safe if you need to take the full output when the process exits. Those events keep coming in after the process has exited and the program has moved on. There's no indication whether the data is complete. If in doubt, the output data will always be incomplete! Seen this here. I'm not sure if async is a good solution in this case.
  • Eric Wood
    Eric Wood over 3 years
    @Curbman, I think T30 was asking "what command" because you are firing the process called "cmd.exe" .
  • SYB
    SYB almost 3 years
    Best example I've found! Thanks
  • Wai Ha Lee
    Wai Ha Lee almost 3 years
  • Evgeny Gorbovoy
    Evgeny Gorbovoy over 2 years
    exceptions caught by general catch(Exception) must be re-thrown, otherwise it swallows the exception which can be awaited by "upper" code. In the given example the debugger will not stop on exception if it happened inside try block
  • Sphynx
    Sphynx over 2 years
    Probably worth mentioning that the Standard Error of the child process ought to go to the Standard Error of this application (e.g. via using (var standardErrorStreamWriter = new StreamWriter(Console.OpenStandardError())) standardErrorStreamWriter.Write(e.Data);). Console.WriteLine writes to the Standard Output instead.
  • k1dfr0std
    k1dfr0std over 2 years
    This is fantastic. Similar to @RichardBarker, I too was able to use this with some transcribing into VB.Net, and this works EXACTLY how I needed it to! Adding Event Handlers for each OutputDataReceived and ErrorDataReceived and appending the data to Public StringBuilders (using them for multiple shell commands) has allowed me to hook the StdOut/StdErr data and process it to provide feedback to my users! WONDERFUL STUFF!
  • Emma Thapa
    Emma Thapa about 2 years
    This saved my day, made my day too. thank you.