如何避免Rust中向less管道输出时覆盖Shell提示符?
问题描述
运行以下Rust程序时,管道到less的输出会覆盖Shell提示符,需要多次按回车才能恢复正常提示符:
use std::process::{Command, Stdio}; use std::io::{self, Write}; fn main() -> io::Result<()> { let mut child = Command::new("less") .args(["--quit-if-one-screen"]) .stdin(Stdio::piped()) .spawn()?; let child_stdin = child.stdin.as_mut().unwrap(); child_stdin.write_all(b"Hello, world!\n")?; drop(child_stdin); Ok(()) }
异常输出:
% cargo run --bin pager Compiling single v0.1.0 (/Users/robenkleene/Developer/Scratch/Rust/single) Finished dev [unoptimized + debuginfo] target(s) in 0.13s Running `target/debug/pager` Hello, world!
期望输出:
% cargo run --bin pager Compiling single v0.1.0 (/Users/robenkleene/Developer/Scratch/Rust/single) Finished dev [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/pager` Hello, world! %
解决方案
问题核心是父进程没有等待less子进程完全退出就提前结束,导致Shell过早输出提示符,被less的终端状态恢复操作覆盖。只需在释放子进程标准输入后,调用child.wait()?阻塞等待子进程终止即可。
修改后的代码:
use std::process::{Command, Stdio}; use std::io::{self, Write}; fn main() -> io::Result<()> { let mut child = Command::new("less") .args(["--quit-if-one-screen"]) .stdin(Stdio::piped()) .spawn()?; let child_stdin = child.stdin.as_mut().unwrap(); child_stdin.write_all(b"Hello, world!\n")?; drop(child_stdin); // 等待less进程完全退出,确保终端状态恢复正常 child.wait()?; Ok(()) }
说明:
spawn()仅启动子进程,父进程会继续执行后续代码并退出,此时Shell会立刻显示提示符,但less可能仍在处理终端状态恢复,导致输出覆盖提示符。child.wait()会阻塞父进程,直到less完全终止并恢复终端状态后,父进程才退出,Shell就能正确显示提示符。
内容的提问来源于stack exchange,提问作者robenkleene
相关产品推荐
相关产品推荐

