Execute shell command and reading stdout to a string

Hi there, I have trouble with a little experiment of mine.

I try to spawn a process, pipe some stuff to stdin and read it's stdout.

Now, I think my problem is, that my solution executes the command, but the output get's printed to the stdout of my rust programming directly
here is my code:

use std::{io::Write, process::Stdio};

pub fn execute(text: &str, shell: &[&str]) -> String {
    let mut command = std::process::Command::new(shell[0])
        .args(&shell[1..])
        .stdin(Stdio::piped())
        .spawn()
        .expect(&format!("failed to spawn process in shell {:?}", shell));

    {
        let stdin = command
            .stdin
            .as_mut()
            .expect("failed to open stdin of command");
        stdin
            .write_all(text.as_bytes())
            .expect("failed to pipe command into shell");
    }

    let output = command
        .wait_with_output()
        .expect("failed to aquire programm output");

    let status: std::process::ExitStatus = output.status;
    if !status.success() {
        eprintln!("error executing command `{}` in shell {}.\nProcess terminated with exit code {}.\nProgram output:\n{}", text, shell[0], status, String::from_utf8(output.stderr).unwrap());
        std::process::exit(1);
    }

    String::from_utf8(output.stdout).expect("programm output was not valid utf-8")
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn exec1() {
        let input = "echo hello";
        let result = execute(input, &["sh"]);
        let expected = "hello";

        assert_eq!(expected, result);
    }
}

Thank you for reading through this
Can anyone help me figure out, what I am doing wrong?

So what's the issue with the code?

the function always returns "" and the output of the program get's printed to stdout.

By default, stdin, stdout and stderr are inherited from the parent. In order to capture the output into this Result<Output> it is necessary to create new pipes between parent and child. Use stdout(Stdio::piped()) or stderr(Stdio::piped()) , respectively.

wait_with_output

So you should use it like this:

let mut command = std::process::Command::new(shell[0])
    .args(&shell[1..])
    .stdin(Stdio::piped())
    .stdout(Stdio::piped())
    .spawn()
    .expect(&format!("failed to spawn process in shell {:?}", shell));
1 Like

Oh of course, thank you!
I was blind to this, and had I not seen your beautiful comment here I would have given in to despair. Now it all makes sense