Module OS.Cmd

Executing commands.

Tool existence and search

Tool search procedure. Given a list of directories, the tool of a command line is searched, in list order, for the first matching executable file. If the tool name is already a file path (i.e. contains a Fpath.dir_sep) it is neither searched nor tested for existence and executability. In the functions below if the list of directories search is unspecified the result of parsing the PATH environment variable with search_path_dirs is used.

Portability. In order to maximize portability no .exe suffix should be added to executable names on Windows, the tool search procedure will add the suffix during the tool search procedure if absent.

val find_tool : ?search:Fpath.t list -> Cmd.t -> (Fpath.t option'e) result

find_tool ~search cmd is the path to the tool of cmd as found by the tool search procedure in search.

val get_tool : ?search:Fpath.t list -> Cmd.t -> (Fpath.t'e) result

get_tool cmd is like find_tool except it errors if the tool path cannot be found.

val exists : ?search:Fpath.t list -> Cmd.t -> (bool, 'e) result

exists ~search cmd is Ok true if find_tool finds a path and Ok false if it does not.

val must_exist : ?search:Fpath.t list -> Cmd.t -> (Cmd.t'e) result

must_exist ~search cmd is Ok cmd if get_tool succeeds.

val resolve : ?search:Fpath.t list -> Cmd.t -> (Cmd.t'e) result

resolve ~search cmd is like must_exist except the tool of the resulting command value has the path to the tool of cmd as determined by get_tool.

val search_path_dirs : ?sep:string -> string -> (Fpath.t list'e) result

search_path_dirs ~sep s parses sep seperated file paths from s. sep is not allowed to appear in the file paths, it defaults to ";" if Sys.win32 is true and ":" otherwise.

Command runs

The following set of combinators are designed to be used with Stdlib.(|>) operator. See a few examples.

WARNING Windows. The ~append:true options for appending to files are unsupported on Windows. This old feature request should be fixed upstream.

Run statuses & information

type status = [
| `Exited of int
| `Signaled of int
]

The type for process exit statuses.

val pp_status : status Fmt.t

pp_status is a formatter for statuses.

type run_info

The type for run information.

val run_info_cmd : run_info -> Cmd.t

run_info_cmd ri is the command that was run.

type run_status = run_info * status

The type for run statuses the run information and the process exit status.

val success : ('a * run_status'e) result -> ('a'e) result

success r is:

  • Ok v if r = Ok (v, (_, `Exited 0))
  • Error _ otherwise. Non `Exited 0 statuses are turned into an error message.

Run standard errors

type run_err

The type for representing the standard error of a command run.

val err_file : ?append:bool -> Fpath.t -> run_err

err_file f is a standard error that writes to file f. If append is true (defaults to false) the data is appended to f.

val err_null : run_err

err_null is err_file File.null.

val err_run_out : run_err

err_run_out is a standard error that is redirected to the run's standard output.

val err_stderr : run_err

err_stderr is a standard error that is redirected to the current process standard error.

Run standard inputs

type run_in

The type for representing the standard input of a command run.

val in_string : string -> run_in

in_string s is a standard input that reads s.

val in_file : Fpath.t -> run_in

in_file f is a standard input that reads from file f.

val in_null : run_in

in_null is in_file File.null.

val in_stdin : run_in

in_stdin is a standard input that reads from the current process standard input.

Run standard outputs

The following functions trigger actual command runs, consume their standard output and return the command and its status. In pipelined runs, the reported status is the one of the first failing run in the pipeline.

Warning. When a value of type run_out has been "consumed" with one of the following functions it cannot be reused.

type run_out

The type for representing the standard output and status of a command run.

val out_string : ?trim:bool -> run_out -> (string * run_status'e) result

out_string ~trim o captures the standard output o as a string. If trim is true (default) the result is passed through String.trim.

val out_lines : ?trim:bool -> run_out -> (string list * run_status'e) result

out_lines is like out_string but the result is splitted on newlines ('\n'). If the standard output is empty then the empty list is returned. Note that trim is applied before lines are splitted, it is not applied on the individual lines.

val out_file : ?append:bool -> Fpath.t -> run_out -> (unit * run_status'e) result

out_file f o writes the standard output o to file f. If append is true (defaults to false) the data is appended to f.

val out_run_in : run_out -> (run_in'e) result

out_run_in o is a run input that can be used to feed the standard output of o to the standard input of another, single, command run. Note that when the function returns the command run of o may not be terminated yet. The run using the resulting input will report an unsucessful status or error of o rather than its own error.

val out_null : run_out -> (unit * run_status'e) result

out_null o is out_file File.null o.

val out_stdout : run_out -> (unit * run_status'e) result

to_stdout o redirects the standard output o to the current process standard output.

Extracting success

The following functions can be used if you only care about success.

val to_string : ?trim:bool -> run_out -> (string, 'e) result

to_string ~trim o is (out_string ~trim o |> success).

val to_lines : ?trim:bool -> run_out -> (string list'e) result

to_lines ~trim o is (out_lines ~trim o |> success).

val to_file : ?append:bool -> Fpath.t -> run_out -> (unit, 'e) result

to_file ?append f o is (out_file ?append f o |> success).

val to_null : run_out -> (unit, 'e) result

to_null o is to_file File.null o.

val to_stdout : run_out -> (unit, 'e) result

to_stdout o is (out_stdout o |> success).

Run specifications

val run_io : ?env:Env.t -> ?err:run_err -> Cmd.t -> run_in -> run_out

run_io ~env ~err cmd i represents the standard output of the command run cmd performed in process environment env with its standard error output handled according to err (defaults to err_stderr) and standard input connected to i. Note that the command run is not started before the output is consumed, see run standard outputs.

val run_out : ?env:Env.t -> ?err:run_err -> Cmd.t -> run_out

run_out ?env ?err cmd is (in_stdin |> run_io ?env ?err cmd).

val run_in : ?env:Env.t -> ?err:run_err -> Cmd.t -> run_in -> (unit, 'e) result

run_in ?env ?err cmd i is (run_io ?env ?err cmd |> to_stdout).

val run : ?env:Env.t -> ?err:run_err -> Cmd.t -> (unit, 'e) result

run ?env ?err cmd is (in_stdin |> run_io ?env ?err cmd |> to_stdout).

val run_status : ?env:Env.t -> ?err:run_err -> ?quiet:bool -> Cmd.t -> (status'e) result

run_status ?env ?err ?quiet cmd is (in_stdin |> run_io ?env ?err ?cmd |> out_stdout) and extracts the run status.

If quiet is true (defaults to false), in_stdin and out_stdout are respectively replaced by in_null and out_null and err defaults to err_null rather than err_stderr.

Examples

Identity miaouw.

let id s = OS.Cmd.(in_string s |> run_io Cmd.(v "cat") |> out_string)

Get the current list of git tracked files in OCaml:

let git = Cmd.v "git"
let git_tracked () =
  let git_ls_files = Cmd.(git % "ls-files") in
  OS.Cmd.(run_out git_ls_files |> to_lines)

Tarbzip the current list of git tracked files, without reading the tracked files in OCaml:

let tbz_git_tracked dst =
  let git_ls_files = Cmd.(git % "ls-files") in
  let tbz = Cmd.(v "tar" % "-cvzf" % p dst % "-T" % "-") in
  OS.Cmd.(run_out git_ls_files |> out_run_in) >>= fun tracked ->
  OS.Cmd.(tracked |> run_in tbz)

Send the email mail.

let send_email mail =
  let sendmail = Cmd.v "sendmail" in
  OS.Cmd.(in_string mail |> run_in sendmail)