2009-11-24 122 views
5

我在嘗試重定向stdin和控制檯應用程序的stdout,以便我可以通過F#與它們交互。但是,取決於控制檯應用程序,明顯的代碼似乎失敗了。下面的F#代碼適用於dirpythonfsi失敗(掛起):在.Net中重定向stdin和stdout

open System 
open System.Diagnostics 

let f = new Process() 
f.StartInfo.FileName <- "python" 
f.StartInfo.UseShellExecute <- false 
f.StartInfo.RedirectStandardError <- true 
f.StartInfo.RedirectStandardInput <- true 
f.StartInfo.RedirectStandardOutput <- true 
f.EnableRaisingEvents <- true 
f.StartInfo.CreateNoWindow <- true 
f.Start() 
let line = f.StandardOutput.ReadLine() 

此掛起蟒蛇,但工程目錄。

這是否與python和fsi一起使用readline還是我犯了一個明顯的錯誤?有沒有可以讓我與F#的fsi或python REPL進行交互的工作?

回答

3

這是您正在查找的代碼(我很方便地在第9章腳本中編寫了代碼;)如前所述,ReadLine會阻塞,直到存在導致各種掛起的完整行。最好的辦法是掛鉤OutputDataRecieved事件。

open System.Text 
open System.Diagnostics 

let shellEx program args = 

    let startInfo = new ProcessStartInfo() 
    startInfo.FileName <- program 
    startInfo.Arguments <- args 
    startInfo.UseShellExecute <- false 

    startInfo.RedirectStandardOutput <- true 
    startInfo.RedirectStandardInput <- true 

    let proc = new Process() 
    proc.EnableRaisingEvents <- true 

    let driverOutput = new StringBuilder() 
    proc.OutputDataReceived.AddHandler(
     DataReceivedEventHandler(
      (fun sender args -> driverOutput.Append(args.Data) |> ignore) 
     ) 
    ) 

    proc.StartInfo <- startInfo 
    proc.Start() |> ignore 
    proc.BeginOutputReadLine() 

    // Now we can write to the program 
    proc.StandardInput.WriteLine("let x = 1;;") 
    proc.StandardInput.WriteLine("x + x + x;;") 
    proc.StandardInput.WriteLine("#q;;") 

    proc.WaitForExit() 
    (proc.ExitCode, driverOutput.ToString()) 

輸出(可以忍受被美化了一番):

val it : int * string = 
    (0, 
    "Microsoft F# Interactive, (c) Microsoft Corporation, All Rights ReservedF# Version 1.9.7.8, compiling for .NET Framework Version v2.0.50727For help type #help;;> val x : int = 1> val it : int = 3> ") 
+0

這是完美的,但我還在擺弄周圍試圖找出如何找到每個命令輸出的開始和結束的。分裂>看起來不太健壯。我試過傳遞「--fsi-server:test」作爲參數,我似乎沒有得到「SERVER-PROMPT>」。有任何想法嗎? – Tristan 2009-11-24 21:38:39

+0

不幸的是,在FSI中沒有辦法知道命令是否正在執行,而不是等待顯示'>',這顯然不是很強大。 (當產生超出任務執行時間的異步任務時,這會變得更加詭異。) 對於自動化,我們使用以下啓發式:等待「\ r \ n>」&&沒有新的輸出寫入第二個或更多。 – 2009-11-24 23:01:20

+0

謝謝。 fsiserver.fs似乎可以在IPC上運行,但是如何像VS shell一樣使用它並不明顯。 – Tristan 2009-11-24 23:23:30

2

我敢打賭,python和fsi都不是真的生成一行文本被閱讀。對ReadLine的呼叫將阻止,直到以回車或換行結束的完整行結束。

嘗試一次讀取一個字符(使用Read而不是ReadLine),看看會發生什麼。

2

這可能是Michael Petrotta所說的。如果是這樣的話,即使閱讀一個角色也無濟於事。你需要做的是使用異步版本(BeginOutputReadLine),這樣你的應用就不會被阻塞。