phil
phil

Reputation: 1446

How to interact with a process through stdout and stdin

I'm trying start an F# interactive subprocess, send code to it through standard input, and receive the response through standard output. Here is the code of my attempt (the command line args are just fsi, which is on the path"):

let readStrStream (stream : StreamReader) =
  let buffer = Array.create 1024 (char 0)
  let bytesReceived = stream.Read(buffer, 0, 1024)
  let chars = buffer |> Array.take bytesReceived
  let str = String.Concat(chars)
  str


let rec loop (proc : Process) = async {
  proc.StandardInput.WriteLine("printf \"iteration\"")

  let output = readStrStream proc.StandardOutput
  printfn "%s" output
  let error = readStrStream proc.StandardError
  printfn "%s" error
  return! loop proc }


let start proc =
  Async.Start(loop proc, cancellationToken = cts.Token)
  { new IDisposable with member x.Dispose() = cts.Cancel }


[<EntryPoint>]
let main argv = 
  let procStart = new ProcessStartInfo(argv.[0], argv.[1..] |> String.concat " ")
  procStart.UseShellExecute <- false
  procStart.RedirectStandardInput <- true
  procStart.RedirectStandardOutput <- true
  procStart.RedirectStandardError <- true
  procStart.WorkingDirectory <- "C:\\Users\\Philip"
  let proc = Process.Start(procStart)
  proc.StandardInput.AutoFlush <- true
  let x = start proc
  let y = Console.ReadLine()
  0

This code does not work. When I run it, it just prints 2 newlines.

If I change the code like so,

let proc = Process.Start(procStart)
Thread.Sleep(10000)

The program prints out

Microsoft (R) F# Interactive version 14.0.23020.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

>

Which is the startup text of fsi.

I did some debugging, and here is what I found. In the first code, both calls to readStrStream return \r\n on the first iteration, and on the second iteration, they first call hangs.

In the second code, the call returns the fsi output.

It seems to me that for some reason the stream is closing down after one call to stream.Read.

I've been playing with other things besides fsi, like python or irb, but they did not work either.

How do I fix this?

Upvotes: 0

Views: 671

Answers (1)

phil
phil

Reputation: 1446

I figured out how to fix it, but I don't entirely understand all that is going on. This answer helped me find the solution. Redirecting stdin and stdout in .Net.

The trick is to use proc.BeginOutputReadLine() and then subscribe to proc.OutputDataReceived instead of calling readline. I think the reason this works has something to do with it being asynchronous.

Upvotes: 1

Related Questions