I see nothing in the standard library that does this for you. Doesn't mean you can't write it yourself. This also means you get to decide how frequently each file descriptor is read and how to combine the data from each of the file descriptors. Here, I attempt to read in chunks using the default BufReader size and prefer to put stdout data first when both descriptors have data.

use std::io::prelude::*; use std::io::BufReader; use std::process::{Command, Stdio}; fn main() { let mut child = Command::new("/tmp/output") .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() .expect("Couldn't run program"); let mut output = Vec::new(); // Should be moved to a function that accepts something implementing `Write` { let stdout = child.stdout.as_mut().expect("Wasn't stdout"); let stderr = child.stderr.as_mut().expect("Wasn't stderr"); let mut stdout = BufReader::new(stdout); let mut stderr = BufReader::new(stderr); loop { let (stdout_bytes, stderr_bytes) = match (stdout.fill_buf(), stderr.fill_buf()) { (Ok(stdout), Ok(stderr)) => { output.write_all(stdout).expect("Couldn't write"); output.write_all(stderr).expect("Couldn't write"); (stdout.len(), stderr.len()) } other => panic!("Some better error handling here... {:?}", other) }; if stdout_bytes == 0 && stderr_bytes == 0 { // Seems less-than-ideal; should be some way of // telling if the child has actually exited vs just // not outputting anything. break; } stdout.consume(stdout_bytes); stderr.consume(stderr_bytes); } } let status = child.wait().expect("Waiting for child failed"); println!("Finished with status {:?}", status); println!("Combined output: {:?}", std::str::from_utf8(&output)) }

The biggest gap is telling when the process has exited. I'm surprised by the lack of a relevant method on Child .

See also How do I prefix Command stdout with [stdout] and [sterr]?

In this solution, there isn't any intrinsic ordering between the file descriptors. As an analogy, imagine two buckets of water. If you empty a bucket and later see that it's been filled up again, you know the second bucket came after the first. However, if you empty two buckets and come back later and both are filled up, you can't tell which bucket was filled first.

The "quality" of interleaving is a matter of how frequently you read from each file descriptor and which file descriptor is read first. If you read a single byte from each in a very tight loop, you might get completely garbled results but these would be the most "accurate" with regard to ordering. Likewise, if a program prints "A" to stderr then "B" to stdout but the shell reads from stdout before stderr, then the result would be "BA", which looks backwards.