Qubit Command
Command-line process running utilities for Rust.
Overview
Qubit Command provides a small, structured API for running external programs, capturing their output, enforcing timeouts, and reporting command failures with clear error values.
Features
- Structured command execution with program and argument vectors
- Explicit shell command support for cases that require shell parsing
- Configurable timeout, working directory, stdin, environment variables, and success exit codes
- Process-tree termination on timeout using Unix process groups and Windows Job Objects
- UTF-8 stdout and stderr text accessors, with raw byte accessors for binary output
- Optional per-stream capture limits plus streaming tee files for large output
- Typed errors for spawn failures, timeouts, failed output reads, and unexpected exit codes
Timeout Behavior
CommandRunner::new() does not enforce a timeout by default. Use
timeout(Duration) when a command must be bounded, or without_timeout() when
the absence of a timeout should be explicit in builder chains.
When a timeout is configured, the runner attempts to terminate the process tree: Unix commands are spawned in a new process group and Windows commands are spawned in a Job Object.
Large Output
By default stdout and stderr are captured without an in-memory byte limit. For commands that can emit large logs, configure capture limits and tee files:
use ;
let output = new
.max_output_bytes
.tee_stdout_to_file
.tee_stderr_to_file
.run?;
if output.stdout_truncated
# Ok::
Quick Start
use Duration;
use ;
let output = new
.timeout
.run?;
println!;
# Ok::
Shell Commands
Prefer structured commands whenever possible:
use ;
let output = new
.run?;
assert_eq!;
# Ok::
Use Command::shell only when shell parsing, redirection, expansion, or
pipes are intentional:
use ;
let output = new
.run?;
assert_eq!;
# Ok::
Output Text
stdout() and stderr() return UTF-8 text by default. Use stdout_bytes() and
stderr_bytes() when a command can emit arbitrary bytes. To replace invalid
UTF-8 bytes with �, enable lossy output on the runner.
If lossy output is disabled and the captured stdout or stderr contains invalid
UTF-8, stdout() / stderr() return Err(str::Utf8Error) from
str::from_utf8—you cannot obtain a &str for that stream. The bytes are still
stored on the returned CommandOutput; use stdout_bytes() / stderr_bytes() to read
the raw output and decode or handle it yourself.
use ;
let output = new
.lossy_output
.run?;
assert_eq!;
# Ok::
Testing
A minimal local run:
To mirror what continuous integration enforces, run the repository scripts from the project root: ./align-ci.sh brings local tooling and configuration in line with CI, then ./ci-check.sh runs the same checks the pipeline uses. For test coverage, use ./coverage.sh to generate or open reports (see the script’s help and any project coverage notes for options such as HTML or JSON).
Contributing
Issues and pull requests are welcome.
- Open an issue for bug reports, design questions, or larger feature proposals when it helps align on direction.
- Keep pull requests scoped to one behavior change, fix, or documentation update when practical.
- Before submitting, run
./align-ci.shand then./ci-check.shso your branch matches CI rules and passes the same checks as the pipeline. When you need to review or improve coverage, use./coverage.shas described under Testing. - Add or update tests when you change runtime behavior, and update this README (or public rustdoc) when user-visible API behavior changes.
By contributing, you agree to license your contributions under the Apache License, Version 2.0, the same license as this project.
License
Copyright © 2026 Haixing Hu, Qubit Co. Ltd.
This project is licensed under the Apache License, Version 2.0. See the LICENSE file in the repository for the full text.
Author
Haixing Hu — Qubit Co. Ltd.
| Repository | github.com/qubit-ltd/rs-command |
| Documentation | docs.rs/qubit-command |
| Crate | crates.io/crates/qubit-command |