Pipe output to another process

My goal it implement fn to be able to run ls | cat via piping output to the next process, run one command wait for the output, grab it and provide it to the next one and execute the next one.

Here is my code:

    // ls | cat | wc -l
    let mut prev_out: Option<std::process::Output> = None;
    for cmd in commands.iter() {
        if let Some(init_cmd) = cmd.split_whitespace().next() {
            let mut command = Command::new(init_cmd);

            if let Some(_) = cmd.split_whitespace().skip(1).collect::<Vec<&str>>().get(0) {
                command.args(cmd.split_whitespace().skip(1));
            }

            if let Some(out) = prev_out {
                command.stdin(Stdio::from(out.stdout));
            } else {
                command.stdin(Stdio::null());
            }

            let ch = command.stdout(Stdio::piped()).spawn()?;
            prev_out = ch.wait_with_output().ok();
        }
    }

But getting the error:

   |
23 |                 command.stdin(Stdio::from(out.stdout));
   |                               ^^^^^ the trait `From<Vec<u8>>` is not implemented for `Stdio`
   |
   = help: the following other types implement trait `From<T>`:
             `Stdio` implements `From<ChildStderr>`
             `Stdio` implements `From<ChildStdin>`
             `Stdio` implements `From<ChildStdout>`
             `Stdio` implements `From<File>`
             `Stdio` implements `From<OwnedFd>`
             `Stdio` implements `From<Stderr>`
             `Stdio` implements `From<Stdout>`

You can spawn the child and write the output of the previous command to Child::stdin. Here an example for ls | cat:

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

fn main() {
    let mut ls = Command::new("ls");
    let mut cat = Command::new("cat");
    cat.stdin(Stdio::piped());

    let out = ls.output().unwrap();

    let mut cat = cat.spawn().unwrap();

    cat.stdin.take().unwrap().write_all(&out.stdout).unwrap();

    let out = cat.wait_with_output().unwrap();

    println!("{}", String::from_utf8(out.stdout).unwrap());
}

Playground.

There's an example of directly piping stdout to stdin in the standard library:

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

let hello = Command::new("echo")
    .arg("Hello, world!")
    .stdout(Stdio::piped())
    .spawn()
    .expect("failed echo command");

let reverse = Command::new("rev")
    .stdin(hello.stdout.unwrap())  // Converted into a Stdio here
    .output()
    .expect("failed reverse command");

assert_eq!(reverse.stdout, b"!dlrow ,olleH\n");
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.