3

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,
Spiderman
  • 1,969
  • 1
  • 14
  • 14
  • This is very similar by the way to https://stackoverflow.com/questions/21011330/how-do-i-invoke-a-system-command-in-rust-and-capture-its-output (possibly duplicate). – chub500 May 14 '20 at 21:08

2 Answers2

5

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).

chub500
  • 712
  • 6
  • 18
  • This setting worked for me ```fn run_command() { let _output = Command::new("/bin/bash") .arg("-c") .arg("docker build -t postgres:latest - < dockers/PostgreSql") .spawn() .expect("failed to execute process"); } ``` – Spiderman May 14 '20 at 22:41
  • Actually during debugging, I changed package name in cargo, but forgot to run new name in executable, so I saw no change whole night I was changing and building and no change , so thought documentation is bad, Documentation is sufficient and my fault I struggled, – Spiderman May 14 '20 at 22:45
0

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

Zombo
  • 1
  • 62
  • 391
  • 407