启动另一个程序然后退出

Den*_*ret 6 process rust

从一个用锈写的程序A开始,我想启动一个程序B,有一个A结束,并且让B正常运行,就好像它是在A终止后从同一个shell手动启动一样.

我目前的计划:

use std::process::Command;

pub fn execute(exe: &str, args: &[&str]) {
    Command::new(exe)
        .args(args)
        .spawn()
        .expect("failed to start external executable");
}

fn main() {
    execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
Run Code Online (Sandbox Code Playgroud)

这失败了.nvim是作为一个孩子启动的,一旦呼叫程序停止就不能正常工作.

如何编写,execute以便调用者程序立即停止并让nvim(或其他程序)正常运行(即使没有任何窗口系统)?

Sve*_*ach 10

经过进一步讨论,我们确定了实际问题:您正在启动的程序应该留在前台,因此它可以从终端读取(Unix 上的后台进程无法执行此操作)。

\n\n

有两种方法可以实现这一目标。第一个也是最简单的方法是在父进程退出之前等待子进程:

\n\n
use std::process::{Command, ExitStatus};\nuse std::io::Result;\n\npub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {\n    Command::new(exe).args(args).spawn()?.wait()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这确保了进程(父进程和子进程)留在前台,因为 shell 正在等待父进程,因此子进程可以从终端读取数据。

\n\n

如果由于某种原因,您无法让父进程在子进程运行时停留,则需要依赖于平台的代码。在 Unix 上,您可以使用exec()家族中的一些系统调用将父进程的映像替换为子进程的映像:

\n\n
use std::process::Command;\nuse std::os::unix::process::CommandExt;\nuse std::io::Error;\n\npub fn execute(exe: &str, args: &[&str]) -> Error {\n    Command::new(exe).args(args).exec()\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

该函数仅在出现错误时返回。否则,过程映像将被新映像替换。从 shell 的角度来看,这仍然是相同的过程,因此 shell 将等待您启动的命令完成。

\n\n

第二种方法的优点似乎微乎其微。它不适用于 Windows,因为 Windows 不支持exec()和朋友。运行该命令时,您会少一个进程,但实际上该进程的资源使用量应该很小 \xe2\x80\x93 它不使用任何 CPU,并且必要时可以交换内存页面。

\n\n

原答案

\n\n
\n

从用 Rust 编写的程序 A 中,我想启动程序 B,让 A 结束,然后让 B 正常运行,就像在 A 终止后从同一 shell 手动启动它一样。

\n
\n\n

这或多或少是您的代码已经在做的事情。不过,与 Unix 系统上直接从 shell 启动的进程有一些区别:

\n\n
    \n
  • 新进程不会包含在 shell 的作业列表中,因此您不能使用 shell 的作业控制命令,例如bgfg
  • \n
  • 新进程将在后台运行,Rust 程序退出后 shell 会立即显示提示。
  • \n
\n\n
\n

这会失败,因为nvim是作为子进程启动的,并且一旦调用程序停止就会被终止。

\n
\n\n

这对于UnixWindows来说都是不正确的。

\n\n
\n

我怎样才能编写执行以便调用程序立即停止并让nvim(或其他程序)正确运行(即使没有任何窗口系统)?

\n
\n\n

这应该正是您的 Rust 代码所做的事情(以及它在我的 Linux 机器上运行时所做的事情)。另一方面,您答案中的代码做了其他事情:它用于用execv()nvim替换Rust 进程。实际上,该进程不会立即停止,并且 shell 保持阻塞状态,直到 nvim 退出。

\n