Unable to pipe to or from spawned child process more than once

前端 未结 1 456
终归单人心
终归单人心 2020-12-16 16:21

I want to be able to use Rust to spawn a child shell, then repeatedly pass it arbitrary commands and process their outputs. I have found plenty of examples online showing me

相关标签:
1条回答
  • 2020-12-16 16:41

    read_to_string is documented as

    Read all bytes until EOF in this source

    Thus, it is waiting until all the input is done, which will never happen until the shell is closed. You can fix this by reading a set amount of data from the output. Here's an example where I removed all the nice error printing you had to show the core of the solution:

    use std::process::{Command, Stdio};
    use std::io::{BufRead, Write, BufReader};
    
    fn main() {
        let mut child_shell = Command::new("/bin/bash")
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()
            .unwrap();
    
        let child_in = child_shell.stdin.as_mut().unwrap();
        let mut child_out = BufReader::new(child_shell.stdout.as_mut().unwrap());
        let mut line = String::new();
    
        loop {
            child_in.write("ls\n".as_bytes()).unwrap();
            child_out.read_line(&mut line).unwrap();
            println!("{}", line);
        }
    }
    

    Here, we use the BufRead trait to allow reading from the input until we have read one line worth. We then print that out and continue on our loop. Of course, there's more than one line of output per line of input, so this will just have more and more waiting to be read.

    In your real code, you will need to have to figure out when to stop reading. This could be really easy if you have fixed-size responses, or really hard if you are trying to deal with a human-interactive program.

    Be careful about using child_shell.stdin or stdout directly, without an Option::as_ref, Option::as_mut or Option::take. Using stdin or stdout directly will move that item out of the Child structure, leaving the Child partially valid. You would no longer be able to call wait or kill on it for example.

    On an unrelated note, you don't need to call trait methods like Error::description(&why). You can just say why.description().

    0 讨论(0)
提交回复
热议问题