【问题标题】:Piping input to stdin prevents read_line() blocking管道输入到标准输入防止 read_line() 阻塞
【发布时间】:2021-08-20 21:09:34
【问题描述】:

我正在尝试编写一个终端程序,该程序通过管道传输 CSV 文件,解析记录,然后根据它们启动测验。我的问题是,一旦我使用io::stdin() 将文件通过管道传输到我的命令行程序中,我就不能再使用io::stdin().read_line() 来获取用户输入,因为它会停止阻塞或等待用户输入。下面是Minimal Reproducible Example

use std::io;

fn main() {
    let stdin = io::stdin();
    println!("Please enter input");
    let mut user_input = String::new();
    stdin.read_line(&mut user_input).expect("Failed to get input");
    println!("The input was {}", user_input);
}

使用cargo run 会导致正常的阻塞行为。使用 echo 'Hello World' | cargo run 会导致 read_line() 在整个程序中不再阻塞。

我认为这不是错误,而是标准输入的工作原理。谁能解释这种行为的细节以及是否有解决方法?

【问题讨论】:

  • 假设您的程序可以确定 CSV 文件的结束位置,您可以将其作为cat quiz.csv - | cargo run 启动,这会将quiz.csv 连接到标准输入(由- 表示)。跨度>

标签: rust stdin


【解决方案1】:

我认为这不是错误,而是标准输入的工作原理。

正确。假设您可以使用 Unix 系统,解决方法是显式打开 /dev/tty

use std::io::{BufReader, BufRead};
use std::fs::File;

fn main() {
    // read piped stuff from stdin...

    // read interactive input from the user
    let mut input = BufReader::new(File::open("/dev/tty").unwrap());
    println!("Please enter input");
    let mut user_input = String::new();
    input.read_line(&mut user_input).expect("Failed to get input");
    println!("The input was {}", user_input);
}

请注意,以这种方式从用户那里获取输入并不是编写命令行程序的惯用方式,因为它不能自动化。相反,请考虑支持命令行选项,这样 clap 这样的 crate 会很方便。

【讨论】:

    猜你喜欢
    • 2019-05-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多