Subprocess
module Core : sig ... end
Here follows the interface defined in the Core
module. This module is included in most of the user-facing modules for convenience, so you may stumble across its documentation in several places.
include module type of Core
type stdin = Core.stdin
type stdout = Core.stdout
type stderr = Core.stderr
type channel = Core.channel
type devnull = Core.devnull
type file = Core.file
type append = Core.append
type pipe = Core.pipe
When the library raises, it always raises a Subprocess_error of string.
module Cmd = Core.Cmd
home of Cmd.t, which is kind of the whole basis of the thing.
module Exit = Core.Exit
types for exit status with lots of extra info for fun and profit.
In and Out are I/O wrappers for process streams. It's thanks to these bad boys we can have such verbose types.
module In = Core.In
module Out = Core.Out
type ('stdin, 'stdout, 'stderr) t = ('stdin, 'stdout, 'stderr) Core.t = {
pid : int;
cmd : ('stdin, 'stdout, 'stderr) Cmd.t;
stdin : 'stdin In.t;
stdout : 'stdout Out.t;
stderr : 'stderr Out.t;
close : ?mode:Unix.wait_flag list -> unit -> Exit.t;
}
The type t
represents a process which may still be running. Some of the higher-level functions don't expose it directly, but almost everything else is implemented in terms of this type.
Apply ()
to the close
property to close any managed file descriptors and wait for the process to exit.
val pp : Stdlib.Format.formatter -> ('stdin, 'stdout, 'stderr) t -> unit
Obligatory pretty printer, for your debugging pleasure.
val show : ('stdin, 'stdout, 'stderr) t -> string
What follows are some helper functions which fetch pipes to a running process for interactive reading and writting. They shadow channels with the same names in the standard library. Probably a good reason to only open Subprocess
within a limited scope.
If you try to use one of these functions to access a stream which isn't a pipe, it's a type error.
val wait :
?mode:Unix.wait_flag list ->
('stdin, 'stdout, 'stderr) t ->
int * Exit.status
Teeny, tiny, leaky wrapper for Unix.waitpid
refer to its documentation
val poll : ('stdin, 'stdout, 'stderr) t -> Exit.status option
Find out if your process has finished executing.
val cmd :
?prog:string ->
?env:string list ->
?block:bool ->
string list ->
(stdin, stdout, stderr) Cmd.t
Helper funtions for constructing Cmd.t. The optional prog
argument is mainly for if you don't want your path to be searched for the executable.
env
is a list of strings with the format "NAME=value"
. block
may be set to false
for non-blocking I/O on pipes. This one setting is used with any pipes which are used for I/O. Remember to catch Sys_blocked_io
when doing I/O with any non-blocking pipes.
Both env
and block
can also be set with combinators.
redirect stdin to a pipe for writing.
redirect stdout to a pipe for reading.
redirect stdout to a pipe for writing.
val channel_in :
Stdlib.in_channel ->
(stdin, 'stdout, 'stderr) Cmd.t ->
(channel, 'stdout, 'stderr) Cmd.t
redirect stdin to an in_channel.
val channel_out :
Stdlib.out_channel ->
('stdin, stdout, 'stderr) Cmd.t ->
('stdin, channel, 'stderr) Cmd.t
redirect stdout to an out_channel.
val channel_err :
Stdlib.out_channel ->
('stdin, 'stdout, stderr) Cmd.t ->
('stdin, 'stdout, channel) Cmd.t
redirect stderr to an out_channel.
redirect stdin to an named file. Similar to <
in the shell.
redirect stdout to an named file. Similar to >
in the shell.
redirect stderr to an named file. Similar to 2>
in the shell.
redirect stdout to an named file for appending. Similar to >>
in the shell.
redirect stderr to an named file for appending. Similar to 2>>
in the shell.
redirect stdout to /dev/null. similar to > /dev/null
in the shell
redirect stderr to /dev/null. similar to 2> /dev/null
in the shell
Set additional environment variables. Variables are passed in as a list of strings with the format "NAME=value"
.
The following functions are generated in a functor to provide a similar interface across several output types. When the documentation speaks about something being "wrapped in the ouptut type", it means the Subprocess_error
is raised in the event of non-zero exit status, and otherwise the value is unchanged.
val exec :
('stdin, 'stdout, 'stderr) Core.Cmd.t ->
f:(('stdin, 'stdout, 'stderr) Core.t -> 'a) ->
'a
Execute a command in, where a handle to the created process will be availbe as the sole input parameter of the function f
. When f
exits, we close any "dangling" file descriptors and wait for the process to exit, finally returning the output value of f
wrapped in the output type.
val exec_joined :
('stdin, Core.stdout, Core.stderr) Core.Cmd.t ->
f:(('stdin, Core.pipe, Core.stdout) Core.t -> 'a) ->
'a
Same as exec
, but stdout and stderr are redirected to the same pipe. This is similar to 2>&1 |
in the shell.
val run : ('stdin, 'stdout, 'stderr) Core.Cmd.t -> unit
Execute the command and wait for it to exit, returning ()
wrapped in the output type.
val write : (Core.stdin, 'stdout, 'stderr) Core.Cmd.t -> input:string -> unit
Execute the command and write the input
string to the stdin of the process.
val write_lines :
(Core.stdin, 'stdout, 'stderr) Core.Cmd.t ->
input:string Stdlib.Seq.t ->
unit
Execute the command and write the input
Seq.t
instance to the stdin of the process, separated by newline characters. If you want to read from stdout while writing, use fold_with
.
val read : ('stdin, Core.stdout, 'stderr) Core.Cmd.t -> string
Execute the command and read its stdout into a string wrapped in the output type.
val lines : ('stdin, Core.stdout, 'stderr) Core.Cmd.t -> string list
Same as read
but with a list of lines wrapped in the output type.
val read_err : ('stdin, 'stdout, Core.stderr) Core.Cmd.t -> string
Same as read
, but reads stderr rather than stdout.
val lines_err : ('stdin, 'stdout, Core.stderr) Core.Cmd.t -> string list
Same as lines
, but reads stderr rather than stdout.
val read_joined : ('stdin, Core.stdout, Core.stderr) Core.Cmd.t -> string
Same as read
but reads stdout and stderr as a single stream.
val lines_joined : ('stdin, Core.stdout, Core.stderr) Core.Cmd.t -> string list
Same as lines
but reads stdout and stderr as a single stream.
val read_both :
?sleep:float ->
('stdin, Core.stdout, Core.stderr) Core.Cmd.t ->
string * string
Same as read_joined
but reads stdout and stderr as a separate strings streams, returning a pair of strings wrapped in the ouput type. This function uses asynchronous I/O internally, so the optional sleep
parameter is provided as a means to pause briefly if output is expected to be slow to avoid pegging the CPU with a loop that does nothing.
val lines_both :
?sleep:float ->
('stdin, Core.stdout, Core.stderr) Core.Cmd.t ->
string list * string list
Same as lines_joined
but reads stdout and stderr as a separate strings streams, returning a pair of string lists wrapped in the ouput type. This function uses asynchronous I/O internally, so the optional sleep
parameter is provided as a means to pause briefly if output is expected to be slow to avoid pegging the CPU with a loop that does nothing.
val fold :
('stdin, Core.stdout, 'stderr) Core.Cmd.t ->
f:('acc -> string -> 'acc) ->
init:'acc ->
'acc
Execute the command. Do a left fold over the lines of output from the processe's stdout. Wraps the accumulated output in the output type.
val fold_err :
('stdin, 'stdout, Core.stderr) Core.Cmd.t ->
f:('acc -> string -> 'acc) ->
init:'acc ->
'acc
Same as fold
, but fold over lines from stderr.
val fold_joined :
('stdin, Core.stdout, Core.stderr) Core.Cmd.t ->
f:('acc -> string -> 'acc) ->
init:'acc ->
'acc
Same as fold
, but joins stdout and stderr into a single stream.
val fold_both :
?sleep:float ->
('stdin, Core.stdout, Core.stderr) Core.Cmd.t ->
f:('acc -> (string, string) Stdlib.result -> 'acc) ->
init:'acc ->
'acc
Same as fold_joined
, but wraps each line of stdin in Ok
and lines of stderr in Error
so they can be distinguished. This function uses asynchronous I/O internally, so the optional sleep
parameter is provided as a means to pause briefly if output is expected to be slow to avoid pegging the CPU with a loop that does nothing.
val fold_with :
?sleep:float ->
?sep:string ->
(Core.stdin, Core.stdout, 'stderr) Core.Cmd.t ->
lines:string Stdlib.Seq.t ->
f:('acc -> string -> 'acc) ->
init:'acc ->
'acc
Execute the command. Feed items from lines
to the process stdin, which will be separated with a newline character by default. Use the optional sep
parameter to change this to another string. While all that is happening, fold over lines from stdout. This function uses asynchronous I/O internally, so the optional sleep
parameter is provided as a means to pause briefly if output is expected to be slow to avoid pegging the CPU with a loop that does nothing.
let&
is a binding operator which wrappes exec
to provide a cleaner syntax, especially when binding multipe processes in a pipeline.
let& proc = cmd ["echo"; "foo"] |> pipe_out in
In_channel.input_all (stdout proc)
(* equivalent to *)
exec (cmd ["echo"; "foo"] |> pipe_out)
~f:(fun proc -> In_channel.input_all (stdout proc))
module Results : sig ... end
The Results
module presents an interface similar to the top-level functions in the Subprocess
module, but the output is wrapped in a result type, where a non-zere exit status becomes Error of
Exit.t
.
module StringResults : sig ... end
The StringResults
module presents an interface similar to the functions in the Results
module, but the output is wrapped in a result type, where a non-zere exit status becomes Error of string
. string
is perhaps less useful than Exit.t
but it composes better. Core
is included here to avoid having to open both Subprocess
and StringResults
.
module Unchecked : sig ... end
The Unchecked
module presents an interface similar to the top-level functions in the Subprocess
module, but the output is wrapped as a pair with Exit.t
as the first element, Core
is included here to avoid having to open both Subprocess
and Unchecked
.
module Exec : sig ... end
The Exec
module is exposed for starting processes without a managing scope. Exec.exec
and Exec.shared_pipe
exist for this purpose.
The following functions expect that their inputs process handles were executed with a Cmd.t
instance where block=false
and will raise this exception if it was not. We could, in principle, prevent this at a type level, but non-blocking I/O operations were added quite late in the design of this library, and I'm still debating whether adding yet another type parameter is wise. For the time being, it's an exception.
Takes a process handle where both stdout and stderr are set to pipe as input and reads streams from each into a string, returning the pair of strings. Raises Non_blocking_io_expected
if I/O is blocking.
val fold_both_proc :
?sleep:float ->
('stdin, pipe, pipe) t ->
f:('acc -> (string, string) Stdlib.result -> 'acc) ->
init:'acc ->
'acc
Takes a process handle where both stdout and stderr are set to pipe and folds over each. See fold_both
for more usage details. Raises Non_blocking_io_expected
if I/O is blocking.
val fold_with_proc :
?sleep:float ->
?sep:string ->
(pipe, pipe, 'stderr) t ->
lines:string Stdlib.Seq.t ->
f:('acc -> string -> 'acc) ->
init:'acc ->
'acc
Takes a process handle where both stdin and stdout are set to pipe and folds over output. See fold_with
for more usage details. Raises Non_blocking_io_expected
if I/O is blocking.