Node.js でコマンドの実行結果を1行ずつ取得する方法
Published: 2022/10/9
Node.js でサーバー側の軽いツールを作ろうとすると、コマンドを実行して、その結果を1行ずつ、それもストリーム処理で、行が取得できた端からその行を await
したくなる。
具体的には、コマンドの実行結果の標準出力を、 Async Generator として for await of
して行を取得したい。
どうやるかが自明ではなかったので、それについて調べたメモ。
答え: readline と child_process.spawn を使う
まず、 Node.js にてコマンドを実行するためには、子プロセス作成系の組込みモジュールである child_process
を使う。
その中で、 exec
の関数は、実行結果の最終的な文字列を全部まとめて取得するしかできないので、 spawn
の方を利用するべき、となる。
spawn
関数の結果は、コールバックにて Buffer が chunk として渡される結果を利用することになり、これは少しやり辛い。
このようなストリーム API に対して、良い感じに行毎に読み込むライブラリは、やはり組み込みである readline
が利用される模様。
(この公式資料のこの部分にもある通り、ストリームから行毎の async iterator を取り出すのには汎用的にこのライブラリを使うらしい)
これらのライブラリを組合せて、以下のようにするとコマンドの実行結果を1行毎に for await of
することができる。
const childProcess = require('node:child_process');
const util = require('node:util');
const readline = require('node:readline');
const lsCommand = childProcess.spawn('ls', ['-al']);
const rl = readline.createInterface({
input: lsCommand.stdout,
crlfDelay: Infinity
});
const main = async () => {
for await (const line of rl) {
console.log(line)
}
}
main()
Tags: nodejsjavascript
関連記事
Promise を扱っている時に microQueue が積まれるタイミング
2022/10/10
(async) 非同期関数と非同期ジェネレータまとめ
2022/6/30
javascript の配列を関数で作成(初期化)する方法
2022/2/16