2016-12-12 2 views
1

Я пытаюсь создать новый интерфейс в Ocaml для приложения на основе терминала. Основная идея заключается в том порождение новый процесс с LWT:Ocaml lwt читает stdout из другого процесса

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()) 

Если бы нормально работать 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

Можете ли вы показать более полный пример, включая то, как вы читаете, и лучшее описание того, что на самом деле делает другой процесс, или, что еще лучше, минимальный исходный код для другого процесса? Что такое «определенный момент»? Можете ли вы читать с помощью 'read_line_opt' какое-то время, то это больше не работает? В каком смысле? Когда вы говорите «конец», вы имеете в виду конец одной строки, конец вывода из другого процесса или что-то еще? Выводит ли другой процесс или закрывает его выходной поток? – antron

+0

Я обновил вопрос с полным примером того, чего я пытаюсь выполнить. – Seneca

+0

Код, который вы опубликовали, не является синтаксически правильным – ivg

ответ

3

Вызов Lwt.read_line_opt возвращает отложенное значение, которое будет определено в будущем, поскольку Some data как только канал считывает строку новой строки с концевыми, либо с None, если канал был закрыт. Канал будет закрыт, если было условие конца файла. Для обычных файлов условие конца файла возникает, когда указатель файла достигает конца файла. Для труб, которые используются для связи с подпроцессом, условие конца файла возникает, когда противоположная сторона закрывает дескриптор файла, связанный с каналом.

Программа ocamldebug не закрывает свои входы или выходы. Это интерактивная программа, которая готова взаимодействовать с пользователем в течение бесконечного промежутка времени или до тех пор, пока пользователь не закроет программу, либо нажав Ctrl-D, либо используя команду quit.

В вашем сценарии вы написали команду info modules на вход канала. Процесс ответил тремя строками (где каждая строка представляет собой фрагмент данных, завершаемый символом новой строки). Затем подпроцесс начал ждать следующего ввода. Вы не видите приглашение (ocd), потому что оно не завершается символом новой строки. Программа не зависала. Он все еще ожидает вывода из подпроцесса, и подпроцесс ожидает ввода от вас (мертвая блокировка).

Если вам действительно нужно отличать выходы от разных команд, вам необходимо отследить приглашение на выходе подпроцесса.Поскольку приглашение не завершается новой строкой, вы не можете полагаться на семейство функций read_line*, так как они буферизируются по строке. Вам нужно прочитать все доступные символы и найти подсказку в них вручную.

С другой стороны, если вам действительно не нужно различать выходы разных команд, вы можете игнорировать приглашение (на самом деле, вы можете даже отфильтровывать его, для более приятного вывода). В этом случае у вас будет две параллельные подпрограммы - одна будет отвечать за подачу ввода, а другая будет считывать все выходные данные и выгружать их без фактического переноса содержимого данных.

+0

Спасибо за продуманный ответ! – Seneca

Смежные вопросы