具有交互式child_process产生的Node.js readline

时间:2014-09-11 13:43:35

标签: node.js stdin readline spawn child-process

我正在使用简单的CLI,其中一个功能是将ssh运行到远程服务器。 这是我的意思的一个例子:

#!/usr/bin/env node

var spawn = require('child_process').spawn;
var readline = require('readline');

var iface =readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
iface.setPrompt("host> ");

iface.on("line", function(line) {
  if (line.trim() == "") {
    return iface.prompt();
  }
  var host = line.split()[0];
  iface.pause(); // PAUSING STDIN!
  var proc = spawn('ssh', [ host, '-l', 'root', '-o', 'ConnectTimeout=4' ], { stdio: [0,1,2] });
  proc.on("exit", function(code, signal) {
    iface.prompt();
  });
});
iface.prompt();

我使用iface.pause()使子进程能够独占于STDIN读取,如果我删除此行,一些符号将由远程服务器捕获,另一个符号将由本地readline捕获。 但是这个pause()确实冻结了stdin,所以如果ssh等待连接太长或者试图要求我输入密码,我就无法发送任何字符,因为stdin已经暂停了。在成功连接之后,我真的不知道ssh如何处理(暂停?)stdin,但不知何故它有效。问题是"如何在交互式子进程工作时将stdin与readline分离而不将其暂停并在子进程完成后将其附加回来?"

2 个答案:

答案 0 :(得分:4)

通过在产卵过程之前添加setRawMode(false)来解决问题。据我所知,这使得节点释放stdin来处理它为处理功能键的按键所做的任何转换。解决的代码版本如下:

var spawn = require('child_process').spawn;
var readline = require('readline');

var iface =readline.createInterface({
  input: process.stdin,
  output: process.stdout
});
iface.setPrompt("host> ");

iface.on("line", function(line) {
  if (line.trim() == "") {
    return iface.prompt();
  }
  var host = line.split()[0];
  iface.pause(); // PAUSING STDIN!
  process.stdin.setRawMode(false); // Releasing stdin
  var proc = spawn('ssh', [ host, '-l', 'root', '-o', 'ConnectTimeout=4' ], { stdio: [0,1,2] });
  proc.on("exit", function(code, signal) {
    // Don't forget to switch pseudo terminal on again
    process.stdin.setRawMode(true); 
    iface.prompt();
  });
});

答案 1 :(得分:0)

对于它的价值,这个问题的一个解决方案可能是不使用子进程来执行ssh客户端连接。有一个名为ssh2的节点的纯JavaScript ssh客户端。它不仅比产生一堆子进程更轻量级,而且可能更容易使用。