【问题标题】:readline.write() does not arrive at stdoutreadline.write() 没有到达标准输出
【发布时间】:2016-08-08 06:28:23
【问题描述】:

我正在尝试为 CLI 编写一个测试,该 CLI 使用 Node.js 的 readline 模块来打印和捕获来自用户的信息,但我似乎无法从标准输出中捕获任何内容。下面是我面临的问题的一个简单版本。

app.js:

#!/usr/bin/env node

const readline = require('readline')
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
})

rl.write('hello\n')
process.exit()

runner.js:

const spawn = require('child_process').spawn

const rl = spawn(__dirname + '/app.js')

rl.stdout.on('data', chunk => {
  console.log('stdout says', chunk.toString())
})

运行runner.js,我希望看到输出stdout says hello,但没有打印。

但是,如果我直接运行 app.jshello 会打印到控制台。此外,如果我使用其他 readline 方法(例如 question),处理程序将触发预期的数据。

为什么这段代码没有按预期工作?怎么改才能工作?

【问题讨论】:

    标签: javascript node.js


    【解决方案1】:

    Readline output to file Node.js相关

    要捕获 rl.write() 的输出,一种解决方案是:在创建 readline 接口实例时将“终端”定义为 true。

    示例代码:

    const readline = require('readline');
    const rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      terminal: true
    });
    

    说明: node.js 中的 readline 模块仅在“终端”为真时将数据写入“输出”流。否则,它只会发出“line”事件,并将数据发送到 line 事件处理程序。根据源码(https://github.com/nodejs/node/blob/master/lib/readline.js):

    首先,检查是否配置了“终端”。如果不是,则使其等于输出流的 isTTY 属性:

    if (terminal === undefined && !(output === null || output === undefined)) {
      terminal = !!output.isTTY;
    }
    ...
    this.terminal = !!terminal;
    

    其次,当rl.write()函数被调用时,它会调用_ttyWrite()或_normalWrite(),这取决于“终端”是否为真:

    Interface.prototype.write = function(d, key) {
      ...
      this.terminal ? this._ttyWrite(d, key) : this._normalWrite(d);
    };
    

    最后,如果调用_ttyWrite(),数据将被发送到输出流。如果调用 _normalWrite(),则忽略输出流:

    //Interface.prototype._ttyWrite will invoke Interface.prototype._insertString, which will call Interface.prototype._writeToOutput
    Interface.prototype._writeToOutput = function _writeToOutput(stringToWrite) {
      ...
      if (this.output !== null && this.output !== undefined)
        this.output.write(stringToWrite);
    };
    

    因此,当 app.js 直接在控制台运行时,会打印“hello”,因为“终端”等于 process.stdout.isTTY,这是真的。但是,当在子进程中执行时,“终端”为假(如果未配置),因为 process.stdout.isTTY 现在未定义。

    【讨论】:

    • 此解决方案有效,但为什么呢? readline 接口已经连接到标准输出,它的输出正在被data 处理程序读取,而不是终端。
    • @user6689821,现在回答中添加了解释:)
    • 谢谢@shaochuancs。我仍然有点困惑为什么write 默认会忽略输出流(如果它不写,为什么称它为写?),但我真的很感谢你浏览代码。
    • @user6689821我也对这个逻辑感到困惑。然而,根据提交历史(github.com/nodejs/node/commit/…),这种行为起源于第一个版本。
    • 所以,如果我将 readline 接口定义为终端,我可以通过管道从生成的孩子中传输标准输入和标准输出吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 2011-08-12
    • 2019-11-08
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    相关资源
    最近更新 更多