Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can't use `Stdio::piped()` with windows `cmd.exe` in Rust?

When I try to start cmd.exe by the following code:

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

fn main() {
    let mut child_cmd = Command::new("cmd.exe")  
        // seems it work well with `/bin/bash` in Linux
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())   // Error emitted here. 
        .spawn()
        .unwrap();   
    // do sth. else
}

I want to redirect the output to pipeline, but it always report The process tried to write to a nonexistent pipe; when I removed .stdout(Stdio::piped()), no errors thrown. Why does this happen?

like image 738
12tall Avatar asked Aug 25 '21 17:08

12tall


1 Answers

EvilTak's comment is spot on. When you redirect STDOUT to a pipe, you'll also have to redirect STDERR to a pipe. The following code no longer errors out:

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

fn main() {
    let mut child_cmd = Command::new("cmd.exe")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())  // Required when redirecting stdout
        .spawn()
        .unwrap();
    // do sth. else
}

While that fixes the immediate issue, I'm not sure what actually causes it. Looking at the CreateProcessW function and the STARTUPINFOW structure it accepts, it looks as though standard I/O redirection is an all-or-nothing option, designated by the STARTF_USESTDHANDLES flag.

The fact that Python exhibits the same behavior suggests that this is in fact a peculiarity of either the Windows API or cmd.exe's implementation.

Either way, I have not done any extensive research to figure out what exactly is going on here.

like image 78
IInspectable Avatar answered Oct 18 '22 07:10

IInspectable