Collecting the output of an external command using OCaml
Asked Answered
H

5

13

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.

Hannis answered 6/2, 2010 at 22:20 Comment(0)
E
15

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

Ermaermanno answered 6/2, 2010 at 22:37 Comment(0)
O
7

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

Outfitter answered 6/2, 2010 at 22:44 Comment(0)
M
4
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
Mooneye answered 22/2, 2010 at 5:35 Comment(0)
B
2

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.

Bimonthly answered 31/1, 2016 at 17:37 Comment(7)
Seems like rashell might be dead these days ? That's unfortunate, it looked greatWheedle
@Wheedle Well I do not know what you mean by dead but for me it currently fills it’s job. What are you missing there? You are welcome to open tickets! :)Shanan
Well it doesn't seem to compile anymore, looks like it references lwt.ppx which as I understand it doesn't exist anymore, replaced by lwt_ppx. Ot is the version in opam just very old ?Wheedle
@Wheedle Well I did not follow the recent development of OCaml and Lwt but maybe it I is now time to catch up. :) if you open a ticket on GitHub you will get some news as it’s is fixed.Shanan
Sure, just did. There was already one, but the issue wasn't really the same so I made a new issue. I expect solving the dependency issue might reveal the other issue from 2017 though. Thanks !Wheedle
Do you know when you'll get a chance to take a look at it ? Just to know if I wait or if I go with something elseWheedle
I will try to have a look at this on the weekend, it should not be that much work.Shanan
S
0

Install batteries and then depend on it as a library, then:

BatUnix.run_and_read 'cmd'

Its interface is:

val BatUnix.run_and_read string -> BatUnix.process_status * string           
Settlings answered 23/3, 2023 at 6:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.