rust 在原始模式下停止命令执行并退出进程

jjhzyzn0  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(207)

下面的代码执行一个命令,然后使您能够使用Ctrl + C退出进程:

use std::process::Command;

use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;

use std::io::{stdin, stdout, Write};

fn main() {
    let stdin = stdin();
    let mut stdout = stdout().into_raw_mode().unwrap();
    let mut command = Command::new("script");

    command
        .arg("-qec")
        .arg("sleep 5 && echo test")
        .arg("/dev/null");

    let output = command.output();

    println!("output: {:?}", output);

    for c in stdin.keys() {
        match c.unwrap() {
            Key::Char(c) => println!("{}\r\n", c),
            Key::Ctrl('c') => {
                println!("Ctrl + C\r\n");
                write!(stdout, "{}", termion::cursor::Show).unwrap();
                std::process::exit(0);
            }
            _ => {}
        }
        stdout.flush().unwrap();
    }
}

Rust Playground
您必须等待命令执行,才能按Ctrl + C并退出程序。
如何在后台监听Ctrl + C,以便即使命令正在运行,进程也可以退出(像在非原始模式下一样中断命令)?

qzlgjiam

qzlgjiam1#

我不确定这是不是最好的方法,但它确实有效。我生成了三个并发线程:一个用于stdout,另一个用于stderr,第三个用于监听Ctrl + C。

use std::{
    io::{BufRead, BufReader},
    process::{Command, Stdio},
};

use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;

use std::io::{stdin, stdout, Write};

fn main() {
    let stdin = stdin();
    
    std::thread::spawn(move || {
        for c in stdin().keys() {
            match c.unwrap() {
                Key::Ctrl('c') => {
                    println!("Ctrl + C\r\n");
                    std::process::exit(0);
                }
                _ => {}
            }
        }
    });
    
    let mut stdout = stdout().into_raw_mode().unwrap();
    
    stdout.flush().unwrap();

    let mut command = Command::new("script");

    command
        .arg("-qec")
        .arg("sleep 5 && echo test")
        .arg("/dev/null");

    command.stdout(Stdio::piped());
    command.stderr(Stdio::piped());

    let mut child = command.spawn().expect("failed to spawn command");
    let stdout_pipe = child.stdout.take().unwrap();
    let stdout_reader = BufReader::new(stdout_pipe);
    let stderr_pipe = child.stderr.take().unwrap();
    let stderr_reader = BufReader::new(stderr_pipe);

    let stdout_thread = std::thread::spawn(move || {
        for line in stdout_reader.lines() {
            if let Ok(line) = line {
                print!("{}\r\n", line);
            }
        }
    });

    let stderr_thread = std::thread::spawn(move || {
        for line in stderr_reader.lines() {
            if let Ok(line) = line {
                print!("{}\r\n", line);
            }
        }
    });

    let status = child.wait().expect("failed to wait for command");

    stdout_thread.join().expect("failed to join stdout thread");
    stderr_thread.join().expect("failed to join stderr thread");

    println!("status: {}", status);
}

注意:ctrl似乎不能在Termion的raw模式下工作。

相关问题