Xwilarg
Xwilarg

Reputation: 414

How to redirect standard and error output in F#

I'm trying to redirect standard and error output in F#

let RunProcess (processInfo : ProcessStartInfo) =
    let str = StringBuilder()
    processInfo.UseShellExecute <- false
    processInfo.RedirectStandardOutput <- true
    processInfo.RedirectStandardError <- true
    let p = new Process()
    p.StartInfo <- processInfo
    p.OutputDataReceived.Add(fun x -> str.Append(x.Data + Environment.NewLine) |> ignore)
    p.ErrorDataReceived.Add(fun x -> str.Append(x.Data + Environment.NewLine) |> ignore)
    p.Start() |> ignore
    p.BeginOutputReadLine()
    p.BeginErrorReadLine()
    str.ToString()

When I do that nothing happen.

However when I set processInfo.RedirectStandardOutput to false things are displayed in my console.

Upvotes: 1

Views: 287

Answers (2)

AMieres
AMieres

Reputation: 5004

This is what I use:

let inline tee    f v   = f v ; v
let inline  (|>!) v f   = f v ; v

let RunProcess (startInfo : ProcessStartInfo) =
    let bufferOutput                      = new StringBuilder()
    let bufferError                       = new StringBuilder()
    let dataHandler               handler = DataReceivedEventHandler(fun sender args -> try handler args.Data with _ -> ())
    let consume   (sb: StringBuilder)     = sb.ToString() |>! (fun _ -> sb.Clear() |> ignore)
    let append    (sb: StringBuilder) txt = sb.Append(txt + "\n") |> ignore
    let outputHandler                     = append bufferOutput   |> dataHandler
    let errorHandler                      = append bufferError    |> dataHandler
    startInfo.RedirectStandardInput      <- true
    startInfo.RedirectStandardOutput     <- true
    startInfo.RedirectStandardError      <- true
    startInfo.UseShellExecute            <- false
    let proc                              = new Process(
                                                StartInfo           = startInfo
                                              , EnableRaisingEvents = true     )
    outputHandler                        |> proc.OutputDataReceived.AddHandler
    errorHandler                         |> proc.ErrorDataReceived .AddHandler
    let r                                 = proc.Start                 () 
    do                                      proc.BeginOutputReadLine   ()
    do                                      proc.BeginErrorReadLine    ()
    do                                      proc.WaitForExit           ()
    let output                            = (consume bufferOutput).Trim()
    let error                             = (consume bufferError ).Trim()
    ((if proc.HasExited then proc.ExitCode else -99999), output, error)

Upvotes: 2

ZiggZagg
ZiggZagg

Reputation: 1427

Process.Start() does not wait for the started process to finish execution. An additional WaitForExit would be required to do that otherwise chances are high you are going to call the StringBuilder ToString before anything has been written to it at all.

Upvotes: 1

Related Questions