Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collecting the output of an external command using OCaml

Tags:

unix

ocaml

What is the right way to call an external command and collect its output in OCaml?

In Python, I can do something like this:

os.popen('cmd').read()

How I can get all of an external program's output in OCaml? Or, better, OCaml with Lwt?

Thanks.

like image 427
Rijhan Djappur Avatar asked Feb 06 '10 22:02

Rijhan Djappur


5 Answers

You want Unix.open_process_in, which is described on page 388 of the OCaml system manual, version 3.10.

like image 86
Norman Ramsey Avatar answered Feb 05 '23 21:02

Norman Ramsey


For Lwt,

val pread : ?env:string array -> command -> string Lwt.t

seems to be a good contender. Documentation here: http://ocsigen.org/docu/1.3.0/Lwt_process.html

like image 41
small_duck Avatar answered Feb 05 '23 20:02

small_duck


let process_output_to_list2 = fun command -> 
  let chan = Unix.open_process_in command in
  let res = ref ([] : string list) in
  let rec process_otl_aux () =  
    let e = input_line chan in
    res := e::!res;
    process_otl_aux() in
  try process_otl_aux ()
  with End_of_file ->
    let stat = Unix.close_process_in chan in (List.rev !res,stat)
let cmd_to_list command =
  let (l,_) = process_output_to_list2 command in l
like image 34
user278471 Avatar answered Feb 05 '23 21:02

user278471


There are lots of examples on PLEAC.

like image 45
Gaius Avatar answered Feb 05 '23 22:02

Gaius


You can use the third party library Rashell which uses Lwt to define some high-level primitives to read output from processes. These primitives, defined in the module Rashell_Command, are:

  • exec_utility to read the output of a process as a string;
  • exec_test to only read the exit status of a process;
  • exec_query to read the output of a process line by line as a string Lwt_stream.t
  • exec_filter to use an external program as a string Lwt_stream.t -> string Lwt_stream.t transformation.

The command function is used to create command contexts on which the previous primitives can be applied, it has the signature:

val command : ?workdir:string -> ?env:string array -> string * (string array) -> t
(** [command (program, argv)] prepare a command description with the
    given [program] and argument vector [argv]. *)

So for instance

Rashell_Command.(exec_utility ~chomp:true (command("", [| "uname" |])))

is a string Lwt.t which returns the “chomped” string (new line removed) of the “uname” command. As a second example

Rashell_Command.(exec_query (command("", [| "find"; "/home/user"; "-type"; "f"; "-name"; "*.orig" |])))

is a string Lwt_stream.t whose elements are the paths of the file found by the command

find /home/user -type f -name '*.orig'

The Rashell library defines also interfaces to some commonly used commands, and a nice interface to the find command is defined in Rashell_Posix – which by the way guarantees POSIX portability.

like image 33
Michaël Le Barbier Avatar answered Feb 05 '23 21:02

Michaël Le Barbier