我试图在Ocaml中为基于终端的应用程序构建一个新的前端。主要想法是使用Lwt生成一个新进程:
let cmd = shell "./otherterminalapp" in
let p = open_process_full cmd;
然后将内容写入流程' stdin,用于在外部应用程序中执行命令。
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 ())
如果您通常使用ocamldebug
运行test.d.byte
,则可获得
在您的终端中关注:
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进程。然而,终端变得敏感。
我在这里遗漏了一些明显的东西?
答案 0 :(得分:3)
对Lwt.read_line_opt
的调用会返回一个延迟值,一旦频道读取以换行符结尾的字符串,将在以后确定为Some data
,如果频道为,则为None
关闭。如果存在文件结束条件,则将关闭该通道。对于常规文件,当文件指针到达文件末尾时,会发生文件结束条件。对于用于与子进程通信的管道,当对方关闭与管道关联的文件描述符时,会发生文件结束条件。
ocamldebug
程序不会关闭其输入或输出。它是一个交互式程序,可以在无限长的时间内与用户交互,或者在用户关闭程序之前,通过点击Ctrl-D
或使用quit
命令。
在您的方案中,您将info modules
命令写入频道的输入。该过程以三行响应(其中每行是以换行符终止的一段数据)。然后子进程开始等待下一个输入。您没有看到(ocd)
提示符,因为它没有被换行符终止。该计划没有挂断。它仍在等待子进程的输出,并且子进程正在等待您的输入(死锁)。
如果您确实需要区分不同命令的输出,则需要在子进程输出中跟踪提示。由于提示未被换行终止,因此您不能依赖read_line*
系列函数,因为它们是行缓冲的。您需要读取所有可用字符并手动查找其中的提示。
另一方面,如果你真的不需要区分不同命令的输出,那么你可以忽略提示(实际上,你甚至可以过滤掉它,以获得更好的输出)。在这种情况下,您将有两个并发子例程 - 一个将负责输入输入,另一个将读取所有输出,并转储它,而不实际携带数据的内容。