execa的子进程如何与父进程通信?

新手上路,请多包涵

一个脚手架里有两个命令,我在主命令里使用execa调用另外一个子命令,子命令通过终端交互后会返回数据,我怎么在主命令中获取到这个数据,使用方法如下

 const {stdout} =await execa("node", ["bin/main.js", "el"], {
   stdio: "inherit",
 });

我尝试使用stdio:pipe,但是我的子命令需要终端交互才能获得数据

阅读 380
avatarAI BotBETA

回答

在使用 execa 库与子进程进行通信时,如果你需要捕获子进程的输出并且子进程依赖于终端交互(如等待用户输入),你需要正确地设置 stdio 选项。在你的情况下,使用 stdio: "inherit" 会使得子进程的输入输出直接继承自父进程(即终端),这通常用于调试或当你希望子进程的输出直接显示在终端上。然而,这样做无法捕获子进程的输出到变量中。

要捕获子进程的输出并且允许终端交互,你可以使用 stdio: ['pipe', 'inherit', 'inherit']。这里的数组分别代表 stdinstdoutstderr 的处理方式:

  • stdin: 'pipe' 允许你从父进程向子进程发送数据(虽然在你的例子中可能不需要)。
  • stdout: 'inherit' 使得子进程的输出显示在终端上(这对于交互是必需的)。
  • stderr: 'inherit' 使得错误输出也显示在终端上(可选,但通常很有用)。

然而,由于你希望捕获输出,你可以将 stdout 设置为 'pipe' 而不是 'inherit'。但这样做会阻止子进程直接接收来自终端的输入(如用户交互)。为了解决这个问题,你可能需要模拟或转发用户的输入到子进程。

解决方案

  1. 如果子命令不需要用户交互

    • stdio 设置为 ['ignore', 'pipe', 'pipe'](忽略输入,捕获输出和错误)。
  2. 如果子命令需要用户交互

    • 这通常更复杂,因为你需要从父进程中模拟或转发这些交互。
    • 一种可能的解决方案是重写子命令,使其接受所有必要的输入作为参数或通过其他非交互方式(如文件、环境变量等)。

示例代码(不需要用户交互):

const { execa } = require('execa');

(async () => {
try {

const { stdout, stderr } = await execa("node", ["bin/main.js", "el"], {
  stdio: ['ignore', 'pipe', 'pipe']
});

console.log('stdout:', stdout);
if (stderr) {
  console.error('stderr:', stderr);
}

} catch (error) {

console.error('Error:', error);

}
})();


注意,这种方法不会显示任何子进程的输出到终端,除非你手动打印它。如果你确实需要显示输出并捕获它,你可能需要更复杂的逻辑来处理输入输出流,这通常涉及到使用 Node.js 的流(streams)功能来监听和转发数据。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏