现在,如果您按Ctrl+C,代码将退出侦听Ctrl+C的loop-但该进程仅在命令执行完成后才会退出.

use std::{
    io::Write,
    process::{Command, Stdio},
    sync::{Arc, Mutex},
    thread,
    time::Duration,
};

use termion::{event::Key, input::TermRead, raw::IntoRawMode};

pub struct CmdRunner {}

impl CmdRunner {
    pub fn run<W: Write + Send + 'static>(&mut self, stdout_mutex: Arc<Mutex<Option<W>>>) {
        let mut command = Command::new("script");

        command.arg("-qec").arg("sleep 6").arg("/dev/null");

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

        let mut child = command.spawn().expect("failed to spawn command");
        let should_exit = Arc::new(Mutex::new(false));
        let should_exit_clone = Arc::clone(&should_exit);
        let mut stdin = termion::async_stdin().keys();

        let handle = std::thread::spawn(move || {
            loop {
                if *should_exit_clone.lock().unwrap() {
                    println!("Exited!");
                    break;
                }

                let input = stdin.next();

                if let Some(Ok(key)) = input {
                    match key {
                        Key::Ctrl('c') => {
                            *should_exit_clone.lock().unwrap() = true;
                        }
                        _ => {}
                    }
                }

                thread::sleep(Duration::from_millis(50));
            }
        });

        child.wait().expect("failed to wait for command");
        
        println!("The command finished executing!");

        *should_exit.lock().unwrap() = true;

        handle.join().unwrap();
    }
}

fn main() {
    let stdout = std::io::stdout().into_raw_mode().unwrap();
    let mut command = CmdRunner {};
    let stdout_mutex = Arc::new(Mutex::new(Some(stdout)));

    command.run(stdout_mutex);
}

这是因为这一行:child.wait().expect("failed to wait for command"),但我不能删除它,因为如果不按Ctrl+C,代码必须等待命令完成.

当按下Ctrl+C时,如何停止命令并正常退出进程?

注意:我删除了使用Arc<Mutex<W>>>来简化代码的代码.

推荐答案

根据我上面的回答,你应该做的不是阻塞child.wait(),你应该使用child.try_wait(),它会告诉你它是否完成了,然后循环睡眠.如果你收到Ctrl-C信号,那么你可以child.kill()它.

在Alex的Rust playground中,他保留了一个线程(循环)和一个主线程循环,但我建议将所有这些都放在一个循环中,并完全抛弃线程.如果您无论如何都睡在主线程中,那么额外的线程有什么好处呢?当您从try_wait()中醒来时,只需判断Ctrl-C w和/或您 Select 用来接收键盘命令或SIGTERM的任何机制.

Rust相关问答推荐

如何在Rust中实现Functor trait?

常量泛型和类型枚举箱有重叠的用途吗?

使用pyo3::Types::PyIterator的无限内存使用量

为什么允许我们将可变引用转换为不可变引用?

无法定义名为&new&的关联函数,该函数的第一个参数不是self

创建Rust中元对象协议的动态对象 Select /重新分配机制

正则表达式中的重叠匹配?(铁 rust 正则式发动机)

作为1字节位掩码的布尔值 struct

在铁 rust 中,如何一次只引用几件事中的一件?

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

Rust proc_macro 和 syn:解析空格

如何强制匹配的返回类型为()?

在 Rust 中使用 `SecTrustSettingsSetTrustSettings` 绑定导致 `errSecInternalComponent`

为什么可以在迭代器引用上调用 into_iter?

是否可以在 Rust 中的特定字符上实现特征?

具有生命周期和以后引用的可变方法

如何在 nom 中构建负前瞻解析器?

以下打印数组每个元素的 Rust 代码有什么问题?

类型组的通用枚举

在 Rust 中组合特征的不同方法是否等效?