【问题标题】:How to send input to a program through stdin in Rust如何在 Rust 中通过标准输入向程序发送输入
【发布时间】:2014-03-04 02:57:47
【问题描述】:

我正在尝试用 Rust 编写一个 shell。 shell 的功能之一是能够将输入重定向到文件,将文件重定向到输入,以及将程序的输出通过管道传输到另一个程序。我正在使用std 中的run::process_output 函数来运行程序并获取它们的输出,但我不知道如何在运行程序后将输入作为标准输入发送到程序。有什么方法可以创建一个直接连接到运行程序的对象并像在标准输入中输入一样推送输入?

【问题讨论】:

  • 可能是std::run::Processstdoutstdin可以得到ReaderWriter

标签: shell stdio rust


【解决方案1】:

这个程序演示了如何启动外部程序并将它们的 stdout -> stdin 一起流式传输:

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();
            }
        }
    }
}

【讨论】:

  • for 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; using format!("{}\n", line.unwrap()); 连接字符串会更惯用吗?
【解决方案2】:

迈克尔回答的更新版本。如果您的输出/输入很小,您可以将其读入字符串并通过以下方式管道返回:

    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();

【讨论】:

    【解决方案3】:

    您需要一个正在运行的进程的句柄来执行此操作。

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

    上面应该可以让你向进程发送任意输入。如果生成的进程读取到 eof,则关闭 stdin 管道将很重要,就像许多程序一样。

    【讨论】:

    • 由于 stdin() 不再存在,这在最近的版本中是否发生了变化,现在它是一个字段?
    猜你喜欢
    • 1970-01-01
    • 2021-03-05
    • 1970-01-01
    • 2018-08-19
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多