有什么方法可以确定 nodejs 子进程是否需要输入或只是发送反馈?

Is there any way to determine if a nodejs childprocess wants input or is just sending feedback?

我有一点空闲时间,所以我决定用子进程重写 JavaScript (NodeJS - ES6) 中的所有 bash 脚本。一切都很顺利,直到我想自动化用户输入。

是的,您可以自动执行用户输入。但是有一个问题 - 您无法确定给定的 data 事件是反馈还是输入请求。至少我找不到办法。

所以基本上你可以这样做:

// new Spawn.
let spawn = require('child_process');
// new ufw process.
let ufw = spawn('ufw', ['enable']);

// Use defined input.
ufw.stdin.setEncoding('utf-8');
ufw.stdout.pipe(process.stdout);
ufw.stdin.write('y\n');

// Event Standard Out.
ufw.stdout.on('data', (data) => {
  console.log(data.toString('utf8'));
});

// Event Standard Error.
ufw.stderr.on('data', (err) => {
  // Logerror.
  console.log(err);
});

// When job is finished (with or without error) it ends up here.
ufw.on('close', (code) => {
  // Check if there were errors.
  if (code !== 0) console.log('Exited with code: ' + code.toString());
  // End input stream.
  ufw.stdin.end();
});

上面的例子完全没问题。但是有两件事让我很头疼:

  1. 是否会 ufw.stdin.write('y\n'); 等到需要它时,如果我有多个输入会怎样?例如 'yes'、'yes'、'no'。一定要写3行stdin.write()吗?

  2. 我用ufw.stdin.write('y\n');的位置是不是有点乱?我认为在我的提示发出输入请求后我需要输入,所以我决定更改我的代码,使我的 stdin.write() 可以在正确的时间 运行,对吧?但是,检查 'right' 时间的唯一方法是在 stdout.on('data', callback) 事件上。这让思考有点困难,因为我需要知道提示是否要求用户输入...

这是我认为完全错误的代码:

// new Spawn.
let spawn = require('child_process');
// new ufw process.
let ufw = spawn('ufw', ['enable']);

// Event Standard Out.
ufw.stdout.on('data', (data) => {
  console.log(data.toString('utf8'));

  // Use defined input.
  ufw.stdin.setEncoding('utf-8');
  ufw.stdout.pipe(process.stdout);
  ufw.stdin.write('y\n');
});

// Event Standard Error.
ufw.stderr.on('data', (err) => {
  // Logerror.
  console.log(err);
});

// When job is finished (with or without error) it ends up here.
ufw.on('close', (code) => {
  // Check if there were errors.
  if (code !== 0) console.log('Exited with code: ' + code.toString());
  // End input stream.
  ufw.stdin.end();
});

我的主要误解是何时使用 stdin 进行用户输入(自动)以及将其放置在我的代码中的什么位置以便在正确的时间使用它,例如,如果我有多个输入的东西像 mysql_secure_installation.

所以我想知道是否可能,但似乎不可能。我发布了一个节点问题,最终被关闭:https://github.com/nodejs/node/issues/16214

I am asking for a way to determine if the current process is waiting for an input.

There isn't one. I think you have wrong expectations about pipe I/O because that's simply not how it works.

Talking about expectations, check out expect. There is probably a node.js port if you look around.

I'll close this out because it's not implementable as a feature, and as a question nodejs/help is the more appropriate place.

因此,如果有人遇到与我相同的问题,您只需将多行写入 stdin 并将其用作预定义值即可。请记住,如果功能更新中的任何输入损坏或错误,最终将中断流:

// new Spawn.
let spawn = require('child_process');
// new msqlsec process.
let msqlsec = spawn('mysql_secure_installation', ['']);
// Arguments as Array.
let inputArgs = ['password', 'n', 'y', 'y', 'y', 'y'];

// Set correct encodings for logging.
msqlsec.stdin.setEncoding('utf-8');
msqlsec.stdout.setEncoding('utf-8');
msqlsec.stderr.setEncoding('utf-8');

// Use defined input and write line for each of them.
for (let a = 0; a < inputArgs.length; a++) {
  msqlsec.stdin.write(inputArgs[a] + '\n');
}

// Event Standard Out.
msqlsec.stdout.on('data', (data) => {
  console.log(data.toString('utf8'));
});

// Event Standard Error.
msqlsec.stderr.on('data', (err) => {
  // Logerror.
  console.log(err);
});

// When job is finished (with or without error) it ends up here.
msqlsec.on('close', (code) => {
  // Check if there were errors.
  if (code !== 0) console.log('Exited with code: ' + code.toString());
  // close input to writeable stream.
  msqlsec.stdin.end();
});

为了完整起见,如果有人想手动填写用户输入,您可以像这样简单地启动给定过程:

// new msqlsec process.
let msqlsec = spawn('mysql_secure_installation', [''], { stdio: 'inherit', shell: true });