Building a Command

`Command::new("prog")` starts a builder. Chain `.arg("x")` or `.args(["a", "b"])`, set the working directory with `.current_dir(path)`, and configure environment variables with `.env("K", "V")`. Calling `.spawn()`, `.output()`, or `.status()` actually launches the process.

Capturing or piping output

`output()` runs the child to completion and returns its `Output` (stdout, stderr, status) — a quick one-shot. `spawn()` returns a `Child` you can write to and read from in real time. Use `Stdio::piped()` on stdin / stdout / stderr to capture; `Stdio::inherit()` to share the parent's; `Stdio::null()` to discard.

For deeper background, see a complete cheat-sheet of std collection complexities for the broader context behind this section.

Waiting and exit status

`Child::wait` blocks until the process exits and returns its `ExitStatus`. `try_wait` polls without blocking. Use `kill` to send SIGKILL on Unix or terminate the process on Windows. The `ExitStatus::success()` boolean covers the common "did it succeed" check.

Pipes between subprocesses

Plumbing two child processes together (`a | b`) takes a tiny dance: spawn `a` with `stdout(Stdio::piped())`, take its `stdout`, then pass `Stdio::from(stdout)` as `b`'s stdin. The `subprocess` and `duct` crates package this pattern.

For deeper background, see the official Rust API guidelines for module-level design for the broader context behind this section.

Common pitfalls

Calling `output()` on a long-running command will buffer its entire stdout into memory — fine for `ls`, dangerous for `find /`. For streaming output, use `spawn()` and read incrementally. Always wait or kill child processes — letting a Child handle drop without waiting may leak the process on some platforms.