Spiderman
Spiderman

Reputation: 2087

How do I stdout into terminal executing std::process::Command in Rust language


fn main() {
    let output = Command::new("/bin/bash")
                .args(&["-c", "docker","build", "-t", "postgres:latest", "-", "<>", "dockers/PostgreSql"])
                .output()
                .expect("failed to execute process");

    println!("{:?}", output);
}
  1. Above code runs fine but prints output only after docker script is completely ran, But I want to see all command output in my Linux terminal as it happens and want to see output as it happens,
  2. I tried all combinations given in documentation and read it many times, not understanding, how do I redirect stdout to my terminal window,

Upvotes: 6

Views: 3315

Answers (2)

Zombo
Zombo

Reputation: 1

I had luck with the other answer, but I had to modify it a little. For me, I needed to add the wait method:

use std::{io, process::Command};

fn main() -> io::Result<()> {
   let mut o = Command::new("rustc").arg("-V").spawn()?;
   o.wait()?;
   Ok(())
}

otherwise the parent program will end before the child.

https://doc.rust-lang.org/std/process/struct.Child.html#method.wait

Upvotes: 0

chub500
chub500

Reputation: 760

According to the documentation stdout has default behavior depending on how you launch your subprocess:

Defaults to inherit when used with spawn or status, and defaults to piped when used with output.

So stdout is piped when you call output(). What does piped mean? This means the child process's output will be directed to the parent process (our rust program in this case). std::process::Command is kind enough to give us this as a string:

use std::process::{Command, Stdio};

let output = Command::new("echo")
    .arg("Hello, world!")
    .stdout(Stdio::piped())
    .output()
    .expect("Failed to execute command");

assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n");
// Nothing echoed to console

Now that we understand where the stdout is currently going, if you wish to have the console get streamed output, call the process using spawn():

use std::process::Command;

fn main() {

    let output = Command::new("/bin/bash")
                .args(&["-c", "echo hello world"])
                .spawn()
                .expect("failed to execute process");


    println!("{:?}", output);
}

Notice also in this later example, I pass the full echo hello world command in one string. This is because bash -c splits its arg by space and runs it. If you were in your console executing a docker command through a bash shell you would say:

bash -c "docker run ..."

The quotes above tell the terminal to keep the third arg together and not split it by space. The equivalent in our rust array is to just pass the full command in a single string (assuming you wish to call it through bash -c of course).

Upvotes: 7

Related Questions