【问题标题】:Ocaml lwt read stdout from other processOcaml lwt 从其他进程读取标准输出
【发布时间】:2016-12-12 09:21:07
【问题描述】:

我正在尝试在 Ocaml 中为基于终端的应用程序构建一个新的前端。主要思想是使用 Lwt 生成一个新进程:

let cmd = shell "./otherterminalapp" in
let p = open_process_full cmd;

然后稍后将内容写入进程的标准输入,以在外部应用程序中执行命令。

 Lwt_io.write_line p#stdin "some command" >>= (fun _ -> Lwt_io.flush p#stdin)

当我用Lwt_io.read_line_opt 读回命令的结果时。我如何阅读直到没有任何行? 我遇到的问题是我的程序只是在某个点挂起。当我使用read_line_opt 阅读时,虽然我读到了结尾,但它似乎只是在等待进程重定向新的输出。

我该如何处理?

我正在尝试做的一个具体示例: (基于终端的应用程序是ocamldebug)

程序源代码:

open Lwt
open Lwt_unix
open Lwt_process
let () =
  let run () =
    let cmd = shell "ocamldebug test.d.byte" in
    let dbgr = open_process_full cmd in
    (((((((Lwt_io.write_line dbgr#stdin "info modules") >>=
            (fun _  -> Lwt_io.flush dbgr#stdin))
           >>= (fun _  -> Lwt_io.read_line_opt dbgr#stdout))
          >>=
          (fun s  ->
             (match s with
              | Some l -> print_endline l
              | None  -> print_endline "nothing here! ");
             Lwt_io.read_line_opt dbgr#stdout))
         >>=
         (fun s  ->
            (match s with
             | Some l -> print_endline l
             | None  -> print_endline "nothing here! ");
            Lwt_io.read_line_opt dbgr#stdout))
        >>=
        (fun s  ->
           (match s with
            | Some l -> print_endline l
            | None  -> print_endline "nothing here! ");
           Lwt_io.read_line_opt dbgr#stdout))
       >>=
       (fun s  ->
          (match s with
           | Some l -> print_endline l
           | None  -> print_endline "nothing here! ");
          Lwt_io.read_line_opt dbgr#stdout))
      >>=
      (fun s  ->
         (match s with
          | Some l -> print_endline l
          | None  -> print_endline "nothing here! ");
         Lwt.return ()) in
  Lwt_main.run (run ())

如果您通常使用test.d.byte 运行ocamldebug,您会得到 在您的终端中执行以下操作:

    OCaml Debugger version 4.03.0

(ocd) info modules
Loading program... done.
Used modules: 
Std_exit Test Pervasives CamlinternalFormatBasics
(ocd) 

当我执行上述程序时,我会打印以下内容:

    OCaml Debugger version 4.03.0

(ocd) Loading program... Used modules: 
Std_exit Test Pervasives CamlinternalFormatBasics

在这里它只是挂起......,我的程序没有退出。即使我这样做 Ctrl-c/Ctrl-c 在我的终端中,有一个活动的 ocamlrun 进程。但是,终端会变得响应。

我在这里遗漏了一些明显的东西?

【问题讨论】:

  • 您能否展示一个更完整的示例,包括您的阅读方式,以及更好地描述其他进程实际在做什么,或者更好的是,提供其他进程的最小源代码?什么是“确定点”?您是否可以使用read_line_opt 阅读一段时间,然后它不再“工作”了?凭什么?当你说“结束”时,你是指一行的结束,另一个进程的输出结束,还是别的什么?其他进程是否真正退出或关闭其输出流?
  • 我用一个完整的例子更新了这个问题。
  • 您发布的代码语法不正确
  • 很抱歉给您带来不便,我已修复语法错误。

标签: ocaml ocaml-lwt


【解决方案1】:

Lwt.read_line_opt 的调用会返回一个延迟值,该值将在将来确定为Some data,一旦通道读取一个以换行符结尾的字符串,或者如果通道已关闭,则为None。如果存在文件结束条件,则通道将关闭。对于常规文件,文件结束条件发生在文件指针到达文件末尾时。对于用于与子进程通信的管道,当对方关闭与管道关联的文件描述符时,就会出现文件结束条件。

ocamldebug 程序不会关闭其输入或输出。它是一个交互式程序,可以通过点击Ctrl-D 或使用quit 命令与用户进行无限时间的交互,或者直到用户关闭程序。

在您的场景中,您将info modules 命令写入通道的输入。该进程以三行响应(其中每一行都是以换行符结尾的一段数据)。然后子进程开始等待下一个输入。您没有看到 (ocd) 提示,因为它没有被换行符终止。程序没有挂断。它仍在等待子进程的输出,子进程正在等待您的输入(死锁)。

如果你真的需要区分不同命令的输出,那么你需要在子进程输出中跟踪提示。由于提示不是由换行符终止的,因此您不能依赖 read_line* 系列函数,因为它们是行缓冲的。您需要阅读所有可用字符并手动在其中找到提示。

另一方面,如果您真的不需要区分不同命令的输出,那么您可以忽略提示(实际上,您甚至可以将其过滤掉,以获得更好的输出)。在这种情况下,您将有两个并发的子例程 - 一个负责提供输入,另一个将读取所有输出并将其转储,而不实际携带数据的内容。

【讨论】:

  • 感谢您的精心回复!
猜你喜欢
  • 1970-01-01
  • 2012-07-18
  • 1970-01-01
  • 2016-03-14
  • 2011-02-17
  • 2015-01-20
  • 1970-01-01
相关资源
最近更新 更多