Node.jsでシェルコマンドを実行させる方法はいくつか存在します。ここでは、「exec」「execSync」「spawn」について動作の違いを確認します。
exec
(非ストリーム形式, 非同期実行)
exec
の動作確認をします。exec.js
というファイルに以下処理を記述します。
const { exec } = require('child_process')
exec('ls -l sample.txt', (err, stdout, stderr) => {
if (err) {
console.log(`stderr: ${stderr}`)
return
}
console.log(`stdout: ${stdout}`)
}
)
console.log('わくわくBank')
コールバックでコマンドの出力結果を取得できます。
$ node exec.js
わくわくBank
stdout: -rwxr-xr-x 1 xxx xxx 21166 Nov 22 01:02 sample.txt
非同期なので わくわくBank
の出力が先に行われています。
ls
の部分を存在しないコマンド( aaa
)にしてエラーを発生させてみます。
$ node exec.js
わくわくBank
stderr: /bin/sh: aaa: command not found
execSync
(非ストリーム形式, 同期実行)
同期実行させたい場合、execSync
を利用します。
execSync
の動作確認をします。execSync.js
というファイルに以下処理を記述します。
const { execSync } = require('child_process')
const stdout = execSync('ls -l sample.txt')
console.log(`stdout: ${stdout.toString()}`)
console.log('わくわくBank')
$ node execSync.js
stdout: -rwxr-xr-x 1 xxx xxx 21166 Nov 22 01:02 sample.txt
わくわくBank
spawn
(ストリーム形式, 非同期実行)
大きいデータを扱う場合、ストリーム形式である spawn
のほうが適しています。
(一度に全てのデータをメモリに読み込むとメモリ不足になるため)
spawn
の動作確認をします。spawn.js
というファイルに以下処理を記述します。
const { spawn } = require('child_process')
const childProcess = spawn('cat', ['sample.txt'])
console.log('process id:' + process.pid)
console.log('child process id:' + childProcess.pid)
childProcess.stdout.on('data', (chunk) => {
console.log(new Date())
console.log(chunk.length)
// console.log(chunk.toString())
})
$ node spawn.js
process id:44066
child process id:44093
2019-11-21T16:32:48.073Z
8192
2019-11-21T16:32:48.076Z
8192
2019-11-21T16:32:48.076Z
4782
spawn
の場合、上記のように少しずつデータを取得しています。
比較として execSync
の動作確認を行います。
const { execSync } = require('child_process')
const stdout = execSync('cat sample.txt')
console.log(`stdout: ${stdout.length}`)
execSync
の場合、以下のように一括でデータを取得しています。
$ node execSync.js
stdout: 21166