📘

Node.js で process.stdin から標準入力を取得するやり方を試したメモ

2023/08/21に公開

概要

Node.js 環境での標準入力のやり方を改めて確認しようと調べたところ、とてもありがたい参考記事があったので手元の環境で動作させながら分からないところを補完したメモ。

動作環境のセットアップ

  • npm init -y
  • npm i @types/node (省略出来そうな気はする)
  • main.ts ファイルの作成
  • 実行は tsx を npx 経由で使う

(手癖で Node.js 環境で TypeScript ファイルを起動させる時には tsx を使うようにしてるけど、deno の方がハンディかも。今回は Node.js API の検証なので deno は使わない。)

コードを眺める

手元でメモを取りながら実際に動かしていたコードが以下。

const buffers: Buffer[] = []

for await (const chunk of process.stdin) {
  console.log({chunk})
  buffers.push(chunk)
}

console.log({buffers})

const buffer = Buffer.concat(buffers)

console.log({buffer})

const text = buffer.toString()

console.log({text})

console.log(text.trim().split("\n"))

検証コードを実行してみる。

> npx tsx main.ts
> a b c
> [ctrl + d]

{ chunk: <Buffer 61 20 62 20 63 0a> }
{ buffers: [ <Buffer 61 20 62 20 63 0a> ] }
{ buffer: <Buffer 61 20 62 20 63 0a> }
{ text: 'a b c\n' }
[ 'a b c' ]

動作内容の確認

process.stdin は Stream.Readable クラスのインスタンスで、Readable は非同期イテレーターとして使うことが出来るとある。
参考:非同期イテレーター/MDN

標準入力(stdin)への入力をデータの流れに見立てており、
for await of ... 構文を使うことでその流れの中からデータを一つずつ取得し任意の処理を行うことが出来るというもの。

検証コードの実行ではコマンドライン上で a b c とタイプしてからエンターキーを入力している。
エンターキーが入力されたことで「エンターキーの入力」も含めた入力データが chunk に格納される。
process.stdin はユーザーが入力の停止の合図を送るまで停止せずループする。
入力の停止の合図を送るには ctrl + d を入力する。(参考:EOFの送信/Stackoverflow

ちなみに、リダイレクトを使いファイルから入力を行った場合、ファイル中のすべての行が一度に読み込まれた。

chunk は Buffer[] 型の配列へ追加される。
Buffer は固定長のバイト配列を表しており、
検証コードの実行で入力した a b c は以下のように表される。

<Buffer 61 20 62 20 63 0a>

これらは入力されたそれぞれの文字とエンターキーの入力(0a)が16進数で表されているものになる。

Buffer.concat は Buffer[] を1つの連続したバイト配列へと変換する。
(単純にバイト配列が結合する。)

Buffer は単なるバイトコードを表す表現に過ぎないため、特定のデータ型として解釈することは出来ない。
特定のデータ型、今回の場合は文字列(string)のデータ型としてプログラム中で扱えるようにするために toString メソッドにより文字列へと変換する。

得られた文字列には改行コード(\n)が含まれているので split メソッドで改行コードを区切り文字として文字列の分割する。
文字列の末尾の改行コードは trim メソッドで除去する。

所感

  • やや大味な印象はあるけど、プログラミングコンテストやコーディングインタビューの(簡単な)問題を手元で動かしたい時には十分なのかなと思った。
  • 今回の検証を経て、Node.js の標準入力にまつわる苦手意識や複雑さへの懸念がかなり薄れた。
  • Node.js v12 からの対応とのことなので(23/08/20 現在)LTS が v18.17.1 の現在は安心して使えるのも良い。

Discussion