I am attempting to write a shell in Rust. One of the functions of a shell is being able to redirect input to a file, redirect a file to input, and pipe output of a program into another program. I am using the run::process_output
functions in std
to run programs and get their output, but I don't know how to send input as if it was stdin to a program after running it. Is there some way to create an object that is directly connected to the ran program and push in input like it was typed in stdin?
This program demonstrates how you can launch external programs and stream their 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();
}
}
}
}
An updated version of Michael's answer. If your output/input is small, you can read it into a string and pipe it back in the following manner:
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With