带有交互式 child_process 生成的 Node.js readline

Pav*_*yov 3 stdin readline spawn child-process node.js

我正在研究简单的 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();
Run Code Online (Sandbox Code Playgroud)

I use iface.pause() to make child process able to read from STDIN exclusively, if I remove this line, some symbols will be catched by remote server, another ones - by local readline. But this pause() really freezes stdin so if ssh waits for connect too long or trying to ask me for password, I can't send any character because stdin is paused. I don't really know how ssh handles (paused?) stdin after successful connect but somehow it works. The question is "How to detach stdin from readline without pausing it while interactive child process is working and to attach it back after child process is finished?"

Pav*_*yov 6

通过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();
  });
});
Run Code Online (Sandbox Code Playgroud)