How to send program entry through stdin in Rust

I am trying to write a shell in Rust. One of the functions of the shell is the ability to redirect input to a file, redirect the file to the input and output the program output to another program. I use functions run::process_outputin stdto start programs and get their output, but I don’t know how to send input, as if it were stdin for the program after it started. Is there a way to create an object that is directly related to the running program and insert the input as if it was entered into stdin?

+4
source share
3 answers

This program demonstrates how you can run external programs and pass them stdout -> stdin together:

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

fn main() {
    // Create some argument vectors for lanuching external programs
    let a = vec!["view", "-h", "file.bam"];
    let outsam = vec!["view", "-bh", "-o", "rust.bam", "-"];

    let mut child = Command::new("samtools")
        .args(&a)
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    let outchild = Command::new("samtools")
        .args(&outsam)
        .stdin(Stdio::piped())
        .spawn()
        .unwrap();

    // Create a handle and writer for the stdin of the second process
    let mut outstdin = outchild.stdin.unwrap();
    let mut writer = BufWriter::new(&mut outstdin);

    // Loop over the output from the first process
    if let Some(ref mut stdout) = child.stdout {
        for line in BufReader::new(stdout).lines() {

            let mut l: String = line.unwrap();
            // Need to add an end of line character back to the string
            let eol: &str = "\n";
            l = l + eol;

            // Print some select lines from the first child to stdin of second
            if (l.chars().skip(0).next().unwrap()) == '@' {
                // convert the string into bytes and write to second process
                let bytestring = l.as_bytes();
                writer.write_all(bytestring).unwrap();
            }
        }
    }
}
+3
source

To do this, you need a handle to the running process.

// spawn process
let mut p = std::process::Command::new(prog).arg(arg).spawn().unwrap();
// give that process some input, processes love input
p.stdin().get_mut_ref().write_str(contents);
// wait for it to complete, you may need to explicitly close stdin above
// i.e. p.stdin().get_mut_ref().close();
p.wait();

The above should allow you to send arbitrary input to the process. It would be important to close the stdin pipe if the spawned process is read until there is one, as many programs do.

+1
source

. / , :

let output = Command::new("ls").arg("-aFl")
        .output().unwrap().stdout;
let output = String::from_utf8_lossy(&output);
println!("First program output: {:?}", output);
let put_command = Command::new("my_other_program")
        .stdin(Stdio::piped())
        .spawn().unwrap();
write!(put_command.stdin.unwrap(), "{}", output).unwrap();
0

Source: https://habr.com/ru/post/1525700/


All Articles