【问题标题】:How to send input to child process created with spawn? nodejs如何将输入发送到使用 spawn 创建的子进程?节点
【发布时间】:2017-05-29 20:26:32
【问题描述】:

我正在运行 Windows 10,并且我有一个程序,我们称之为 program,它可以从命令行运行。运行时,它响应用户输入的命令。用户输入命令,按下返回键,程序打印响应。这个程序不是我做的,也没有源码,所以无法修改。

我想在 Node.js 中运行这个程序,并让我的 Node.js 程序充当用户,向它发送命令并获得响应。我像这样生成我的程序:

var spawn = require('child_process').spawn;
var child = spawn('program');

child.stdout.on('data', function(data) {
    console.log(`stdout: ${data}`);
});

然后我尝试向它发送一个命令,例如,help

child.stdin.write("help\n");

然后什么也没有发生。如果我手动运行程序,输入help,然后按回车键,我会得到输出。我希望 Node.js 能够像人类用户一样运行程序、发送输入并接收输出。我假设stdin.write() 会向程序发送一个命令,就好像用户在控制台中键入它一样。但是,由于程序没有响应,我认为情况并非如此。如何发送程序输入?

我见过很多类似的问题,但不幸的是,他们的作者报告为“有效”的解决方案对我不起作用。

【问题讨论】:

  • 用 vim 试试。我的意思是写这个var child = spawn('vim');child.stdin.write("q\n");。这应该运行vim 并退出。有用吗?

标签: node.js


【解决方案1】:

这对我有用。我使用child_process exec 创建了一个子进程。在这个子进程Promise 中,我正在处理作为参数给出的cmd 的i/o 部分。它并不完美,但它的工作原理。

不需要任何人工输入的示例函数调用。

executeCLI("cat ~/index.html");

与 aws cli 交互的示例函数调用。这里

executeCLI("aws configure --profile dev")

自定义executeCLI函数的代码。

var { exec } = require('child_process');
async function executeCLI(cmd) {
  console.log("About to execute this: ", cmd);
  var child = exec(cmd);
  return new Promise((resolve, reject) => {
    child.stdout.on('data', (data) => {
      console.log(`${data}`);
      process.stdin.pipe(child.stdin);
    });

    child.on('close', function (err, data) {
      if (err) {
        console.log("Error executing cmd: ", err);
        reject(err);
      } else {
        //   console.log("data:", data)
        resolve(data);
      }
    });
  });
}

【讨论】:

  • 这是如何将数据发送到衍生进程的?您只需执行一个命令。我们正在寻找一种方法让进程使用 spawn 运行,然后执行命令。
  • @TheFool 当我们将参数“cmd”作为字符串 var 传递时;我们可以在字符串中传递任何参数或标志。例如,给定“aws configure --profile dev”或“/scripts/blabla.sh -a 1 -b 2”
  • 你不明白我在说什么,你也不明白这个问题。是的,您确实执行了命令,但您没有首先在后台运行该进程。您开始该过程,捕获其输出并结束该过程。这不是问题。
  • 顺便说一句,答案是 child_process.spawn 然后 proc.write(data) 在任何时候运行的进程。
【解决方案2】:

从 Win10 CMD 或 Git Bash 运行时,这对我有用:

console.log('Running child process...');
const spawn = require('child_process').spawn;
const child = spawn('node');
// Also worked, from Git Bash:
//const child = spawn('cat');

child.stdout.on('data', (data) => {
    console.log(`stdout: "${data}"`);
});

child.stdin.write("console.log('Hello!');\n");
child.stdin.end(); // EOF

child.on('close', (code) => {
    console.log(`Child process exited with code ${code}.`);
});

结果:

D:\Martin\dev\node>node test11.js
Running child process...
stdout: "Hello!
"
Child process exited with code 0.

我也尝试过像这样运行aws configure,首先它不起作用,因为我只发送了一行。但是当为预期的四个输入值发送四行时,它起作用了。

也许您的程序需要 stdin 的特殊属性,例如作为真正的终端,因此不接受您的输入?
还是您忘记使用child.stdin.end(); 发送EOF? (如果您从我的示例中删除该调用,则孩子将永远等待输入。)

【讨论】:

    【解决方案3】:

    从浏览器中提取用户输入代码并使用fs 模块将该代码保存到系统上的文件中。将该文件设为“program.cpp”并将用户数据输入保存在文本文件中。

    由于我们可以使用 g++ 在终端上编译 c++ 代码,因此我们将使用 child_process 访问我们的系统终端并运行用户的代码。

    execFile可以用来执行我们的程序

    var { execFile } = require('child_process');
    
    execFile("g++", ['program.cpp'], (err, stdout, stderr) => {
        if (err) {
            console.log("compilation error: ",err);
        } else{
            execFile ('./a.out' ,['<', 'input.txt'], {shell: true}, (err, stdout, stderr) => {
                console.log("output: ", stdout);         
            })
        }
    })
    
    

    在这段代码中,我们只需要child_process 并使用它的execFile 函数。

    • 首先我们编译 program.cpp 中的代码,这会创建一个默认的 a.out 作为输出文件
    • 然后我们将 a.out 文件与 input.txt 中存在的输入一起传递

    因此您可以在终端中查看生成的输出并将其传回给用户。

    更多详情您可以查看:Child Processes

    【讨论】:

      猜你喜欢
      • 2012-12-29
      • 1970-01-01
      • 2015-01-27
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 2013-01-11
      • 2018-04-16
      • 2015-01-18
      相关资源
      最近更新 更多