Wait() for child process after collecting output

I've written a small program that's supposed to send output from both stderr and stdoutof a child process to a single function, as the output is happening.

It "works" and does exactly what I need... but I'm unable to call wait() on the child to perform the required cleanup.

use std::io::BufRead;
use std::io::BufReader;
use std::process::{Command, Stdio};
use std::thread;

#[derive(Debug)]
enum Output {
    Out,
    Err,
}

fn main() {
    let mut child = Command::new("ping")
        .arg("1.1.1.1")
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .expect("failed to spawn");

    let reader = BufReader::new(child.stdout.expect("failed to capture stdout"));
    let stdout_thread = thread::Builder::new()
        .name("stdout-thread".to_string())
        .spawn(|| {
            reader
                .lines()
                .filter_map(|s| s.ok())
                .for_each(|line| do_something(Output::Out, &line));
            println!("OUT DONE!");
        });

    let reader = BufReader::new(child.stderr.expect("failed to capture stderr"));
    let stderr_thread = thread::Builder::new()
        .name("stderr-thread".to_string())
        .spawn(|| {
            reader
                .lines()
                .filter_map(|s| s.ok())
                .for_each(|line| do_something(Output::Err, &line));
            println!("ERR DONE!");
        });

    stdout_thread
        .expect("stdout_thread join handle")
        .join()
        .expect("stdout_thread join failed");
    stderr_thread
        .expect("stderr_thread join handle")
        .join()
        .expect("stderr_thread join failed");

    //child.wait();
}

fn do_something(output: Output, line: &str) {
    println!("{:?}: {}", output, line);
}

Uncommenting the child.wait(); would cause the following compiler error.

   |
21 |     let stderr = child.stderr;
   |                  ------------ value moved here
...
54 |     child.wait();
   |     ^^^^^ value borrowed here after partial move
   |
   = note: move occurs because `child.stderr` has type `std::option::Option<std::process::ChildStderr>`, which does not implement the `Copy` trait

I understand the error and the cause of it but I'm stuck about how to implement this in a proper way, meaning that child is cleaned up as required while the output is still processed as it is happening instead of only after the process has already terminated.

Any help would be appreciated.

Call take() on the Options re

1 Like

Thanks a lot!