我在尝试弄清楚如何与子进程交互方面遇到了一些困难。
我目前的做法大致如下:
1. 创建进程:
let mut program = match Command::new(command)
.args(arguments)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Ok(child) => child,
Err(_) => {
println!("Cannot run program '{}'.", command);
return;
}
};
将其传递给一个无限循环(直到用户退出),该循环读取和处理输入并侦听输出,就像这样(并将其写入屏幕):
fn listen_for_output(program: &mut Child, output_viewer: &TextViewer) {
match program.stdout {
Some(ref mut out) => {
let mut buf_string = String::new();
match out.read_to_string(&mut buf_string) {
Ok(_) => output_viewer.append_string(buf_string),
Err(_) => return,
};
}
None => return,
};
}
调用read_to_string
会阻塞程序直到进程退出。据我所见,read_to_end
和read
也似乎会阻塞。如果我尝试运行像ls
这样立即退出的命令,它可以正常工作,但是对于像python
或sbcl
这样不会退出的命令,只有手动杀死子进程后才能继续执行。基于这个答案,我修改了代码以使用
BufReader
: fn listen_for_output(program: &mut Child, output_viewer: &TextViewer) {
match program.stdout.as_mut() {
Some(out) => {
let buf_reader = BufReader::new(out);
for line in buf_reader.lines() {
match line {
Ok(l) => {
output_viewer.append_string(l);
}
Err(_) => return,
};
}
}
None => return,
}
}
然而,问题仍然存在。它会读取所有可用的行,然后阻塞。由于该工具应该与任何程序一起使用,因此在尝试读取之前,无法猜测输出何时结束。似乎也没有办法为BufReader
设置超时。