从标准输入读取所有文本到字符串

Read all text from stdin to a string

我正在 Node.js 中编写一个程序(在某些情况下)想要充当一个简单的过滤器:从标准输入读取所有内容(直到文件末尾),进行一些处理,写入结果到标准输出。

'read everything from stdin' 部分是怎么做的?到目前为止我找到的最接近的解决方案,似乎要么一次从控制台工作一行,要么只在标准输入是文件而不是管道时工作。

get-stdin 就可以了。


在您问题的字里行间读到一些注释。

既然你标记了问题 "synchronous",我只注意到标准输入在 node.js 中是异步的。上面的库是最简单的。它将整个输入作为字符串或缓冲区处理。

如果可能,最好以流式方式编写程序,但有些用例对于流式处理是可行的(即字数统计),而有些则不可行(即反转输入)。

此外,"one line at a time from the console" 是终端缓冲击键的产物。如果你想要一些 "I'm sorry I asked" 级别的详细信息,请查看令人惊叹的 the TTY Demystified.

如果您使用的是 linux,则不需要第三方软件包。当然,请考虑您的性能需求,但这两行将起作用:

const fs = require("fs");
const data = fs.readFileSync("/dev/stdin", "utf-8");

Jan 在下面的评论中指出,更便携的解决方案是使用 0,因为这是 POSIX 标准。所以,你可以简单地使用:

const fs = require("fs");
const data = fs.readFileSync(0, "utf-8");

data 现在是一个包含来自标准输入的数据的字符串,解释为 utf 8

我在 Node 11+

中使用了以下内容
 async function read(stream) {
   const chunks = [];
   for await (const chunk of stream) chunks.push(chunk); 
   return Buffer.concat(chunks).toString('utf8');
 }

用法:

const input = await read(process.stdin);

我的这个样板很像上面评论中描述的解决方案——在顶层提供它,因为这是最简单的方法,不应该只在评论。

var fs = require('fs');
var data = fs.readFileSync(0, 'utf-8');
// Data now points to a buffer containing the file's contents

除了@Patrick Narkinsky 的解决方案,我在这里还没有看到实际同步的解决方案。但是 @Patrick Narkinsky 的回答不适用于 Windows。 似乎是一个 node.js 错误。如果你想了解细节,请随意进入这个 github 问题的兔子洞,但我在阅读一个小时后放弃了。

  1. https://github.com/aws/aws-cdk/issues/11314 此处报告的问题
  2. https://github.com/nodejs/node/issues/35997 该库的贡献者创建了一个节点问题
  3. https://github.com/libuv/libuv/pull/3053 一个 nodejs 贡献者提交了一个带有修复(?)(尚未合并)的 PR

我在那里找不到解决方法(我可能掩盖了它),但是 I accidentally stumbled on a solution to the problem. It's not pretty, but it works。由于那个 link 只显示了如何记录进度,我不得不根据自己的需要修改它:

import fs from 'fs';
const BUFSIZE = 256;
const buf = Buffer.alloc(BUFSIZE);
let bytesRead;
let stdin = '';

export function stdinToString(): string {
  do {
    // Loop as long as stdin input is available.
    bytesRead = 0;
    try {
      bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, null);
    } catch (e) {
      if (e.code === 'EAGAIN') {
        // 'resource temporarily unavailable'
        // Happens on OS X 10.8.3 (not Windows 7!), if there's no
        // stdin input - typically when invoking a script without any
        // input (for interactive stdin input).
        // If you were to just continue, you'd create a tight loop.
        throw 'ERROR: interactive stdin input not supported.';
      } else if (e.code === 'EOF') {
        // Happens on Windows 7, but not OS X 10.8.3:
        // simply signals the end of *piped* stdin input.
        break;
      }
      throw e; // unexpected exception
    }
    if (bytesRead === 0) {
      // No more stdin input available.
      // OS X 10.8.3: regardless of input method, this is how the end
      //   of input is signaled.
      // Windows 7: this is how the end of input is signaled for
      //   *interactive* stdin input.
      break;
    }
    // Process the chunk read.
    stdin += buf.toString(undefined, 0, bytesRead);
  } while (bytesRead > 0);

  return stdin;
}

我已经编程十多年了,这是第一次 do while 让我的代码更干净 :) 没有它,如果不存在标准输入数据,这个函数就会挂起——有人可能会争辩说是 link.

代码中的错误

这回答了原始问题并且适用于所有操作系统。