Module std.process

Process execution.

run and run_argv execute a command to completion and capture its output. start launches a Command (never through a shell) and returns a Child whose piped stdio are ordinary Stream<bytes> and Sink<bytes> values. Command.output(CaptureLimits { timeout, max_output_bytes }) captures both output streams with a runtime limit and a shared byte budget.

start and Command.output inherit the parent's environment and working directory. start_with_options and Command.output_with_options accept a SpawnOptions snapshot: Environment.Inherit(bindings) overlays inherited variables, while Environment.Clear(bindings) passes only explicit bindings, including none. Neither operation changes process-global state. Both spawn paths use the same owned Child and native lifecycle.

A Child owns its process until it is reaped. wait suspends the calling task and holds no thread while the child runs: it parks on the I/O reactor (a pidfd on Linux, a kqueue process filter on FreeBSD and macOS) or, on Windows, on the system thread pool's wait for the process handle. Any number of tasks may wait on children at once. The reaped status is kept, so a second wait returns it again and a later terminate or kill does nothing. Dropping a Child that is still running kills and reaps it.

A child's stdout and stderr streams are select sources on every native host. A losing selection leaves its data available for the next receive. Windows retains at most 64 KiB of completed output per pipe; pending reads use overlapped I/O and release their buffers after cancellation completes.

Examples

import std.encoding.utf8;
import std.process;

fn main() {
    let output = process.run_argv("printf", ["<%s>", "hello world"]).expect("printf runs");
    println(output.stdout);

    var command = process.command("cat", []);
    command.stdin = process.Stdio.Piped;
    command.stdout = process.Stdio.Piped;
    let child = process.start(command).expect("cat starts");
    let input = child.stdin().expect("stdin is piped");
    let echoed = child.stdout().expect("stdout is piped");
    input.send("ping".to_bytes()).expect("cat reads");
    input.finish();
    for chunk in echoed {
        println(utf8.decode_lossy(chunk));
    }
    println(f"{child.wait():?}");
}
import std.process;

fn main() {
    let options = process.SpawnOptions {
        environment: .Clear([process.EnvVar { name: "LANG", value: "C" }]),
        cwd: .None,
    };
    let command = process.command("tool", ["--version"]);
    let output = command.output_with_options(
        process.CaptureLimits { timeout: 5s, max_output_bytes: 4096 },
        options,
    ).expect("tool runs with only the approved binding");
    println(output.stdout);
}

Contents

Functions

Function run

pub fn run(command: string) -> Result<CommandOutput, ProcessError>

Run a shell command and capture its status and output. Waiting for output or exit suspends the caller; cancellation reaps the child.

Function run_argv

pub fn run_argv(command: string, args: Vec<string>) -> Result<CommandOutput, ProcessError>

Run a program without the shell and capture its status and output. Both output streams drain concurrently while the caller is suspended.

Function command

pub fn command(program: string, args: Vec<string>) -> Command

A Command for program with args and every stream inherited.

Function inherited_options

pub fn inherited_options() -> SpawnOptions

Options matching the defaults of start and Command.output.

Function start_with_options

pub fn start_with_options(command: Command, options: SpawnOptions) -> Result<Child, ProcessError>

Launch with per-child environment bindings and an optional working directory.

Bindings are applied in order; the last binding for a name wins. Name comparison follows the host (case-insensitive on Windows). Empty names, names containing = or NUL, values containing NUL, and empty or NUL-containing working directories return InvalidArguments without launching a child. Other operating-system failures return LaunchFailed. Diagnostics never include environment values.

Use an absolute program path with cwd: resolving a relative program path against a changed working directory is platform-dependent. Program lookup and any environment variables added by the child follow the host's rules; clearing inheritance is not a sandbox.

Function start

pub fn start(command: Command) -> Result<Child, ProcessError>

Launch command without waiting. A program that cannot be launched is Err(ProcessError.LaunchFailed).

Types

Enum Stdio

Where a child's standard stream goes.

Variants

Inherit

Share this program's stream.

Null

Connect the stream to the null device.

Piped

Connect the stream to a pipe the parent takes once from the Child.

Struct Command

A program, its arguments and its stdio. The arguments reach the program exactly as given; no shell interprets them.

Fields

program: string
args: Vec<string>
stdin: Stdio
stdout: Stdio
stderr: Stdio

Struct EnvVar

An explicit child environment binding. Empty values are allowed.

Fields

name: string
value: string

Enum Environment

The environment of a new child, without changing the parent's environment.

Variants

Inherit(Vec<EnvVar>)

Inherit the parent's environment, then apply these bindings.

Clear(Vec<EnvVar>)

Start with no inherited variables, then apply these bindings. Clear([]) requests an explicitly empty environment.

Struct SpawnOptions

Optional per-child configuration for start_with_options and Command.output_with_options. Existing Command literals stay unchanged.

Fields

environment: Environment
cwd: Option<string>

None inherits the parent's working directory. A relative directory resolves from the parent's working directory.

Struct CaptureLimits

Limits for Command.output.

Fields

timeout: duration

A positive runtime limit, including draining output and waiting for exit.

max_output_bytes: i64

The maximum retained raw stdout and stderr bytes together; zero permits no output. A chunk that would exceed this limit is rejected before append.

Enum ExitStatus

How a process ended.

Variants

Exited(i64)

The process exited with this code.

Signalled(i64)

A signal with this number ended the process (Unix only).

Struct CommandOutput

Captured output from a completed command.

Fields

status: ExitStatus
stdout: string
stderr: string

Enum ProcessError

Structured process failures.

Variants

InvalidArguments(string)
LaunchFailed(string)
NotPiped

The stream was not Stdio.Piped or was already taken.

System(i64)

The operating system refused a wait or signal with this error code.

TimedOut(duration)

Command.output reached its configured runtime limit.

OutputLimitExceeded(i64)

Command.output would retain more than this many raw output bytes.

Struct Child

A running or finished child process.

Fields

handle: ChildHandle

Inherent methods

impl Command

fn output(self, limits: CaptureLimits) -> CommandOutput fails ProcessError

Run without a shell and capture stdout and stderr within limits.

Captures a snapshot without changing this command's configuration. Stdout and stderr are piped regardless of their command settings. Stdin may be inherited or null; Piped is refused because this operation does not expose a writer. Use start for interactive input.

A nonzero exit is ordinary CommandOutput.status data. Exceeding either limit returns a structured error without partial output, after killing and reaping a child that is still running. Cancellation does the same. The byte budget bounds retained raw output. Operating-system pipes, backend read buffers, the current chunk, allocation capacity and UTF-8 conversion have separate memory costs.

fn output_with_options(self, limits: CaptureLimits, options: SpawnOptions) -> CommandOutput fails ProcessError

Capture output with a per-child environment and working directory. Limits, stdio, cancellation and cleanup follow output.

impl Child

fn id(self) -> i64

The child's operating-system process ID.

fn stdin(self) -> Result<stream.Sink<bytes>, ProcessError>

Take the write end of the child's stdin pipe. Finishing the sink closes the pipe, so the child reads end of input.

fn stdout(self) -> Result<stream.Stream<bytes>, ProcessError>

Take the read end of the child's stdout pipe.

fn stderr(self) -> Result<stream.Stream<bytes>, ProcessError>

Take the read end of the child's stderr pipe.

fn wait(self) -> ExitStatus fails ProcessError

Wait for the child to exit and reap it. The task suspends and holds no thread; a wait cancelled by scope within releases its watch and leaves the child running and unreaped.

fn try_wait(self) -> Result<Option<ExitStatus>, ProcessError>

Reap the child if it has exited, without waiting.

fn terminate(self) -> Result<(), ProcessError>

Ask the child to stop: SIGTERM on Unix. Windows has no request to stop, so this terminates the child like kill. A reaped child is not signalled.

fn kill(self) -> Result<(), ProcessError>

Stop the child at once: SIGKILL on Unix, TerminateProcess on Windows. A reaped child is not signalled.

fn close(consume self)

Release the child at scope exit, killing and reaping it first if it is still running.