【问题标题】:Node.js readline with interactive child_process spawning具有交互式 child_process 生成的 Node.js readline
【发布时间】:2014-09-11 13:43:34
【问题描述】:

我正在开发简单的 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 读取,如果我删除此行,一些符号将被远程服务器捕获,另一些符号将被本地读取行捕获。 但是这个pause() 确实冻结了标准输入,所以如果 ssh 等待连接时间过长或试图向我询问密码,我无法发送任何字符,因为标准输入已暂停。我真的不知道成功连接后ssh如何处理(暂停?)标准输入,但它以某种方式工作。问题是“如何在交互式子进程工作时从 readline 中分离标准输入而不暂停它,并在子进程完成后将其附加回来?”

【问题讨论】:

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


    【解决方案1】:

    通过在生成过程之前添加setRawMode(false) 解决了这个问题。据我了解,这使得节点从它为处理功能键的按键所做的任何转换中释放标准输入。解决后的代码如下:

    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();
      });
    });
    

    【讨论】:

    • 您是否尝试过直接从childprocess 写入标准输入?我的意思是 proce.stdin.on('data', iface.input.write.bind(iface.input)) 也可能有效。
    • 谢谢,这非常有帮助!
    【解决方案2】:

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

    【讨论】:

    • 很高兴在这里见到你@mscdex。我已经尝试使用您的ssh2 模块,它非常适合一次在多个服务器上并行执行任务。但是通过ssh2 实现交互式shell 对我来说真的很头疼。为了不破坏 tab-autocomplete 和其他原始 tty 操作,以及处理窗口大小调整等,我必须执行的操作数量让我认为使用本机 ssh 更简单。
    猜你喜欢
    • 1970-01-01
    • 2020-12-12
    • 2014-07-05
    • 2011-12-16
    • 2017-09-09
    • 2020-05-10
    • 2016-08-24
    • 1970-01-01
    • 2013-02-26
    相关资源
    最近更新 更多