std::process::Command output() method error handling hazards #73126
Description
Hi. Normally, Rust makes it difficult to accidentally write buggy code. This is one of its great strengths. However, the API of output()
on std::process::Command
API has two serious error handling hazards:
- It requires the user to explicitly fish out the program's exit status and check it.
- It requires the user to explicitly deal, somehow, with the program's stderr output (if any).
See the example below.
I think this is very difficult to fix with the current return value from output()
. It seems to me that there should be a new function whose behaviour is as follows:
- Unless the user explictly called
.stderr(...)
when building theCommand
, any nonempty stderr is treated as an error, giving anErr
return value (whoseDebug
impl prints the stderr output). - Nonzero exit status is treated as an error, giving an
Err
return value, - In case of nonzero exit status together with nonempty stderr output (the usual case) the error object contains both (and its
Debug
impl displays both). - The returned value is purely the actual stdout.
I don't know what this should be called. Unfortunately the name output
has been taken for the more hazardous, raw, function. Which we must retain because if you want to run a command that sometimes succeeds returning nonzero (eg, diff
) you need something like it.
(See also #70186 which is about the return value from spawn()
. I am about to file another issue about the return value from wait()
)
use std::process::*;
use std::io::stdout;
use std::io::Write;
fn main() {
let command = ["ls","--no-such-option"];
let output = Command::new(command[0])
.args(&command[1..])
.output()
.expect("output() failed");
println!("Output from {:?}:", &command);
stdout().write_all(output.stdout.as_slice()).expect("write failed");
println!("All went well!")
}
Actual output:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 0.72s
Running `target/debug/playground`
Standard Output
Output from ["ls", "--no-such-option"]:
All went well!
Expected output:
Some kind of compiler warning. Or something in the docs to say not to use .output()
(and, therefore, something convenient to use instead).