Search code examples
rustpiperust-cargo

How to capture the output of a process piped into a Rust program?


I know how to read the command line arguments, but I am having difficulties reading the command output from a pipe.

  1. Connect a program (A) that outputs data to my Rust program using a pipe:

    A | R
    
  2. The program should consume the data line by line as they come.

    $ pwd | cargo run should print the pwd output.

    OR

    $ find . | cargo run should output the find command output which is more than 1 line.


Solution

  • Use BufRead::lines on a locked handle to standard input:

    use std::io::{self, BufRead};
    
    fn main() {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            let line = line.expect("Could not read line from standard in");
            println!("{}", line);
        }
    }
    

    If you wanted to reuse the allocation of the String, you could use the loop form:

    use std::io::{self, Read};
    
    fn main() {
        let stdin = io::stdin();
        let mut stdin = stdin.lock(); // locking is optional
    
        let mut line = String::new();
    
        // Could also `match` on the `Result` if you wanted to handle `Err` 
        while let Ok(n_bytes) = stdin.read_to_string(&mut line) {
            if n_bytes == 0 { break }
            println!("{}", line);
            line.clear();
        }
    }