Environment and Process Management

Command

The std::process::Command struct is a process builder that configures every aspect of a child process before launching it: the executable path, individual or batched arguments, working directory, environment variables, and standard I/O descriptors.

Builder Configuration Methods

Method Signature Summary Description
Command::new(program) new<S: AsRef<OsStr>>(program: S) -> Command Creates a new Command for program, resolved via PATH if not a path.
.arg(arg) arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command Appends a single command-line argument.
.args(iter) args<I, S>(&mut self, args: I) -> &mut Command Appends multiple command-line arguments from an iterator.
.current_dir(dir) current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Command Sets the working directory solely for the child process.
.env(key, val) env<K, V>(&mut self, key: K, val: V) -> &mut Command Inserts or overrides an environment variable for the child.
.envs(iter) envs<I, K, V>(&mut self, vars: I) -> &mut Command Inserts or overrides multiple (key, val) pairs.
.env_remove(key) env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command Removes an inherited environment variable from the child.
.env_clear() env_clear(&mut self) -> &mut Command Clears all inherited environment variables, starting from an empty environment.

Passing Arguments Correctly: .arg() vs Combined Strings

Each distinct flag and option value must be passed as a separate argument via .arg() or .args(). Passing "--out-dir /tmp/build" as a single .arg() passes a single string containing a space rather than two arguments.

use std::env;
use std::ffi::OsStr;
use std::process::Command;

fn main() {
    let mut cmd = Command::new("rustc");
    cmd.arg("--edition=2024")
        .args(["--crate-type", "lib"])
        .current_dir(env::temp_dir())
        .env("RUST_BACKTRACE", "1")
        .env_remove("RUSTFLAGS");

    // Inspect configured command state before execution
    println!("Program: {:?}", cmd.get_program());

    let collected_args: Vec<&OsStr> = cmd.get_args().collect();
    println!("Args:    {:?}", collected_args);
    println!("Has CWD: {}", cmd.get_current_dir().is_some());
}
Program: "rustc"
Args:    ["--edition=2024", "--crate-type", "lib"]
Has CWD: true

Constructing a Clean Hermetic Environment with .env_clear()

By default, a Command inherits all environment variables from the parent process. Security-sensitive tools, build systems, and test runners often call .env_clear() to strip inherited secrets (such as API tokens or LD_PRELOAD) and whitelist only required variables:

use std::env;
use std::io;
use std::process::Command;

fn main() -> io::Result<()> {
    let mut cmd = Command::new("rustc");
    cmd.arg("--version")
        .env_clear()
        .env("CustomKey", "HermeticValue");

    // Preserve PATH so the OS can locate `rustc` and its linker/libraries
    if let Some(path) = env::var_os("PATH") {
        cmd.env("PATH", path);
    }
    if let Some(sysroot) = env::var_os("SystemRoot") {
        cmd.env("SystemRoot", sysroot); // Required on Windows
    }

    let status = cmd.output()?.status;
    println!("Hermetic child succeeded: {}", status.success());
    Ok(())
}
Hermetic child succeeded: true

Reusing a Command Builder

Because .spawn(), .output(), and .status() take &mut self rather than consuming self by value, a configured Command can be executed repeatedly in a loop or augmented with additional .arg() calls between runs.