Nodejs ChildProcess
child_processモジュールは似たマナーでchild processを出すための機能を提供して、popen(3)と似ているが同一ではない。この能力はchild_process.spawn()関数で主に提供される:
code:js
const { spawn } = require('child_process');
ls.stdout.on('data', (data) => {
console.log(stdout: ${data});
});
ls.stderr.on('data', (data) => {
console.error(stderr: ${data});
});
ls.on('close', (code) => {
console.log(child process exited with code ${code});
});
デフォルトで、stdin、stdout、stderrによるパイプは親Node.jsプロセスと出された子との間で作られる。これらのパイプは制限された(そしてプラットフォーム固有の)能力を持つ。もしchild processがキャプチャーされた出力なしの制限の超過でstdoutに書くなら、child processはより多くのデータを受け入れるためのパイプバッファを待機するためにブロックする。これはシェルでのパイプの振る舞いと同様である。もし出力が消費されないなら、{ stdio: 'ignore' }を使うこと。
もしoptionsオブジェクトで渡したなら、コマンドルックアップはoptions.env.PATH環境変数を使うことで行われ、そうでない場合、process.env.PATHが使われる。Windows環境変数が大文字小文字を区別しない事実を見るために、Node.jsはすべてのenvキーを辞書式に並び替え、コマンドルックアップを行うために大文字小文字を区別しないPATHと合うことを選ぶ。これはPATH変数の複数区別を持つenvオプションにオブジェクトを渡す時にWindows上に問題を招く。
便宜上、child_processモジュールはchild_process.spawn()とchild_process.spawnSync()の代わりに同期と非同期の一握りを提供する。これらの代わりはchild_process.spawn()もしくはchild_process.spawnSync()の上に実装される。
child_process.exec(): 完了したときにコールバック関数にstdoutとstderrを渡すことで、シェル内のシェルを出して、コマンドを起動する。
child_process.execFile(): デフォルトでシェルを初めに出さずに直接コマンドを出すchild_process.exec()を除いて似ている。
child_process.fork(): 新しいNode.jsプロセスを出し、親と子の間にメッセージを送られることを出したIPC通信チャンネルの特定のモジュールを呼び出す。
child_process.execSync(): Node.jsイベントループをブロックするchild_process.exec()の同期バージョン。
child_process.execFileSync(): Node.jsイベントループをブロックするchild_process.execFile()の同期バージョン。
確かなユースケースによって、自動シェルスクリプトのように、同期対応はより便利になる。しかし、たくさんのケースで、同期メソッドは出されたプロセスが完了している間にイベントループを停止しているためパフォーマンス上重要な影響を持つことができる。
非同期プロセス設定
child_process.spawn()、child_process.fork()、child_process.exec()、child_process.execFile()メソッドは他のNOde.js APIの典型的な慣用非同期プログラミングパターンをすべて従う。
様々なメソッドはChildProcessインスタンスを返す。正しいイベントがchold processのサイクルの間に起こる時に呼ばれるリスナー関数を登録するためのparent processを与えるために、これらのオブジェクトはNode.js EventEmitter APIを実装する。
child_process.exec()とchild_process.execFile()メソッドはchild processが終了したときに呼び出されることを特定されたオプションのコールバック関数を自動的に与える。
Windowsで.batと.cmdファイルを出すために
child_process.exec()とchild_process.execFile()の間の区別の重要性はプラットフォーム上でとても基にできる。デフォルトでシェルを出さないので、Unix系OS(Unix、Linux、macOS)child_process.execFile()はより効果的にすることができる。しかし、Windows上で、.batと.cmdファイルはターミナルなしで実行できず、それゆえchild_process.execFile()を使って起動させることができない。Windows上で起動しているとき、.batと.cmdファイルは、シェルオプション準備、child_process.exec()もしくは(シェルオプションとchild_process.exec()でする)引数としてcmd.exeを出して、.batもしくは.cmdファイルを渡すことでchild_process.exec()を使うと呼び出すことができる。もしスクリプトファイル名がスペースを含むなら引用する必要がある。
code:js
// On Windows Only...
const { spawn } = require('child_process');
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.error(data.toString());
});
bat.on('exit', (code) => {
console.log(Child exited with code ${code});
});
code:js
// OR...
const { exec, spawn } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
});
// Script with spaces in the filename:
const bat = spawn('"my script.cmd"', 'a', 'b', { shell: true }); // or:
exec('"my script.cmd" a b', (err, stdout, stderr) => {
// ...
});
child_process.exec(command/, options//, callback/)
command 空白で分けられた引数によって、起動するコマンド
options
cwd child processの動作している現在のディレクトリィ Default: null。
env key-valueのペアの環境 Default: process.env.
encoding Default: 'utf8'
timeout Default: 0
maxBuffer Largest amount of data in bytes allowed on stdoutもしくはstderr上で与えられたバイトでのデータの最も大きい量。もし超えた場合、child processは終了し、出力は切り捨てられる。maxBufferとUnicodeでの警告を見ること。 Default: 1024 * 1024。
killSignal Default: 'SIGTERM'
windowsHide Windowsシステム上で作られたであろうサブプロセスコンソールを隠す。 Default: false.
callback プロセスを終了する時に出力するために呼び出す。
error <Error>
stdout <string> | <Buffer>
stderr <string> | <Buffer>
Returns: <ChildProcess>
生成された出力をバッファリングするのに、シェル内のcommandを実行する時にシェルを出す。command文字列はシェルによって直接処理されるexec関数に渡して、特殊な文字(シェルではとても基本)が応じて処理する必要がある:
code:js
exec('"/path/to/test file/test.sh" arg1 arg2');
// Double quotes are used so that the space in the path is not interpreted as
// a delimiter of multiple arguments.
exec('echo "The \\$HOME variable is $HOME"');
// The $HOME variable is escaped in the first instance, but not in the second.
この関数に汚染されたユーザー入力を渡さないこと。入力を構成しているシェルメタキャラクターは任意のコマンド実行をトリガーするために使われる。
もしコールバック関数が提供されたなら、引数(error、stdout、stderr)を呼ぶ。成功したうえで、errorはnullになる。エラー上で、errorはErrorのインスタンスになる。error.codeプロパティはerror.signalが処理を終了したシグナルをセットする間のchild processの終了コードである。0以外の終了コードはエラーとみなされる。
コールバックに渡すstdoutとstderr引数はchild processのstdoutとstderr出力を含む。デフォルトで、Node.jsがUTF-8として出力をデコードして、コールバックに文字列を渡す。encodingグオプションはstdoutとstderr出力をデコードするために使ったキャラクターエンコーディングを指定するために使うことができる。もしencodingが'buffer'か認識されていないキャラクターエンコーディングであるなら、Bufferオブジェクトはかわりにコールバックを渡す。
code:js
const { exec } = require('child_process');
exec('cat *.js missing_file | wc -l', (error, stdout, stderr) => {
if (error) {
console.error(exec error: ${error});
return;
}
console.log(stdout: ${stdout});
console.error(stderr: ${stderr});
});
もしtimeoutが0より大きい場合や子がtimeoutミリセコンドより長く起動している場合、親は(デフォルトはSIGTERM)killSignalプロパティによって識別したシグナルを送る。
exec(3)POSIXシステムコールと異なり、child_process.exec()は存在しているプロセスと入れ替えずコマンドを実行するためにシェルを使う。 もしこのメソッドがutil.promisify()されたバージョンとして呼び出された場合、stdoutとstderrプロパティによってObjectのPromiseを返す。返されたChildProcessインスタンスはchildプロパティとしてPromiseを付けられる。エラー(0以外のexit codeで結果を出すエラーを含んでいる)の原因で、コールバックで与えた同じerrorオブジェクトだが、stdoutとstderrの二つの追加のプロパティによって、拒否されたプロミスが返される、 code:js
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function lsExample() {
const { stdout, stderr } = await exec('ls');
console.log('stdout:', stdout);
console.error('stderr:', stderr);
}
lsExample();
child_process.execFile(file/, args/, options//, callback/)
file 起動するためのファイルのパスもしくは名前
args 文字列のリスト引数
options
cwd child processの動作している現在のディレクトリィ Default: null。
env key-valueのペアの環境 Default: process.env.
encoding Default: 'utf8'
timeout <number> Default: 0
maxBuffer stdoutもしくはstderr上で与えられたバイトでのデータの最も大きい量。もし超えた場合、child processは終了し、出力は切り捨てられる。maxBufferとUnicodeでの警告を見ること。 Default: 1024 * 1024。
killSignal Default: 'SIGTERM'
windowsHide Windowsシステム上で作られたであろうサブプロセスコンソールを隠す。 Default: false.
windowsVerbatimArguments Windowsでは、引数の引用やエスケープは行われない。Unix上では無視される。Default: false
shell もしtrueなら、シェルの中でコマンドを起動する。Unix上では'/bin/sh'が使われ、Windows上ではprocess.env.ComSpecが使われる。異なるシェルは文字列として特定することができる。シェル必要条件とデフォルトWindowsシェルを見ること。Default: false (no shell). callback プロセスが終了するとき、出力を呼ぶ。
error <Error>
stdout <string> | <Buffer>
stderr <string> | <Buffer>
Returns: <ChildProcess>
child_process.execFile()関数はデフォルトでシェルを出さないことを除いてchild_process.exec()に似ている。むしろ、特定された実行できるファイルはchild_process.exec()よりすこし効率的で新しいプロセスとして直接出される。
child_process.exec()と同じオプションはサポートされている。シェルが出されてから、I/Oリダイレクションやファイルグロビングのような振る舞いはサポートされていない。
code:js
const { execFile } = require('child_process');
const child = execFile('node', '--version', (error, stdout, stderr) => { if (error) {
throw error;
}
console.log(stdout);
});
コールバックに渡されるstdoutとstderr引数はchild processのstdoutとstderr出力を含んでいる。デフォルトで、Node.jsはUTF-8として出力をデコードして、コールバックに文字列を渡す。encodingオプションはstdoutとstderr出力をデコードするのに使用されるキャラクターエンコーディングを指定するのに使うことができる。もしencodingが'buffer'であるか、認識されないキャラクターエンコーディングであるなら、Bufferオブジェクトは代わりにコールバックに渡される。
もしこのメソッドがutil.promisify()されたバージョンとして呼び出された場合、stdoutとstderrプロパティによってObjectのPromiseを返す。返されたChildProcessインスタンスはchildプロパティとしてPromiseを付けられる。エラー(0以外のexit codeで結果を出すエラーを含んでいる)の原因で、コールバックで与えた同じerrorオブジェクトだが、stdoutとstderrの二つの追加のプロパティによって、拒否されたプロミスが返される、 code:js
const util = require('util');
const execFile = util.promisify(require('child_process').execFile);
async function getVersion() {
const { stdout } = await execFile('node', '--version'); console.log(stdout);
}
getVersion();
もしshellオプションが利用可能であるなら、この関数の認識されない使用入力を渡さないこと。入力に含んでいるシェルメタキャラクターは任意のコマンド実行をトリガーするために使われる。
child_process.fork(modulePath/, args//, options/)
modulePath childで起動するためのモジュール
args 文字列引数のリスト
options
cwd child processの動作している現在のディレクトリィ Default: null。
detached parent processと独立して起動するためにchildを準備する。(プラットフォームに依存する振る舞いを特定すること。options.detachedを見ること) env key-valueのペアの環境 Default: process.env.
execPath child processを作るために使用されるexecutable
execArgy executableに渡した文字列引数のリスト。Default: process.execArgv.
serialization プロセスとの間で送信しているメッセージを使ったいくつかのシリアライズ化を指定する。可能な値は'json'、'advanced'である。より詳細なことはAdvanced Serializationをみること。 silent もしtrueなら、childのstdin、stdout、stderrはparentにパイプされる。そうでない場合、parentから継承される。より詳細なことは、child_process.spawn()のstdioの'pipe'と'inherit'オプションを見ること。
stdio child_process.spawn()のstdioを見ること。このオプションが提供されたとき、silentを上書きする。もし配列バリアントが使われるなら、値'ipc'の確定した1つのアイテムを含む。
windowsVerbatimArguments Windowsでは、引数の引用やエスケープは行われない。Unix上では無視される。Default: false
child_process.fork()メソッドは新しいNode.jsプロセスを出すために使うchild_process.spawn()の特別なケースである。child_process.spawn()のような、ChildProcessオブジェクトは返される。返されたChildProcessはparentとchildの間の後ろと前に渡されるメッセージにビルドインする追加の通信チャンネルをもつ。詳細はsubprocess.send()を見ること。 Node.jsを出したことを心に留めて、child processは二つの間に立てられたIPC通信チャンネルの例外によって親を独立する。様々なプロセスは、V8インスタンスの所有によって、メモリ所持を持つ。追加のリソースアロケーションが要求するので、多くの子を出すためにNode.jsプロセスは推奨されない。
デフォルトで、child_process.fork()はparent processのprocess.execPathを使うことで新しいNode.jsインスタンスを出す。optionsオブジェクトのexecPathプロパティは使われるべき代わりの実行パスを与える。
Node.jsプロセスはchild process上で環境変数NODE_CHANNEL_FDを使うことで認識した記述子(fd)を使ってparent processによって通信するカスタムexecPathを起動する。
fork(2)POSIXシステムコールと違い、、child_process.fork()は現在のプロセスを選択しない。 child_process.spawn()で利用できるシェルオプションはchild_process.fork()によってサポートされず、もしセットされているなら無視される。
child_process.spawn(command/, args//, options/)
command コマンドを起動する
args 文字列引数のリスト
options
cwd child processの動作している現在のディレクトリィ
detached parent processと独立して起動するためにchildを準備する。(プラットフォームに依存する振る舞いを特定すること。options.detachedを見ること) env key-valueのペアの環境 Default: process.env.
argv0 child processに送るarg[0]の値を明示的にセットする
detached parent processを独立して動かすためにchildを前準備する。プラットフォームに依存する振る舞いを指定すること。(詳しくはoptions.detached) serialization プロセスとの間で送信しているメッセージを使ったいくつかのシリアライズ化を指定する。可能な値は'json'、'advanced'である。より詳細なことはAdvanced Serializationをみること。 windowsVerbatimArguments Windowsでは、引数の引用やエスケープは行われない。Unix上では無視される。これはThis is set to true automatically when shell is specified and is CMD. Default: false.Default: false
shell もしtrueなら、シェルの中でコマンドを起動する。Unix上では'/bin/sh'が使われ、Windows上ではprocess.env.ComSpecが使われる。異なるシェルは文字列として特定することができる。シェル必要条件とデフォルトWindowsシェルを見ること。Default: false (no shell). windowsHide Windowsシステム上に作られるサブプロセスコンソールウィンドウを隠す。Default: false.
child_process.spawn()メソッドは、argsのコマンドライン引数によって、与えられたコマンドを使うことで新しいプロセスを出す。もし出されたなら、argsのデフォルトは空の配列になる。
もしshellオプションが可能なら、この関数に汚染されたユーザー入力を渡さないこと。シェルメタキャラクタを含む何かの入力が任意のコマンド実行をトリガーするために使われる。
第3引数は、デフォルトで、追加のオプションを指定するのに使われる:
code:js
const defaults = {
cwd: undefined,
env: process.env
};
プロセスが出されてから作業しているディレクトリを指定するためにcwdを使うこと。もし与えられていないなら、デフォルトは現在の作業ディレクトリを継承するべき。
新しいプロセスを見ることができる環境変数を指定するためにenvを使うこと。デフォルトはprocess.env。
envでundefined値は無視される。
stdout、stderrとexitコードを捕らえるために、ls -lh /usr`を起動する例:
code:js
const { spawn } = require('child_process');
ls.stdout.on('data', (data) => {
console.log(stdout: ${data});
});
ls.stderr.on('data', (data) => {
console.error(stderr: ${data});
});
ls.on('close', (code) => {
console.log(child process exited with code ${code});
});
例:ps ax | grep sshを起動するためのとても精巧な方法
code:js
const { spawn } = require('child_process');
const ps = spawn('ps', 'ax'); const grep = spawn('grep', 'ssh'); ps.stdout.on('data', (data) => {
grep.stdin.write(data);
});
ps.stderr.on('data', (data) => {
console.error(ps stderr: ${data});
});
ps.on('close', (code) => {
if (code !== 0) {
console.log(ps process exited with code ${code});
}
grep.stdin.end();
});
grep.stdout.on('data', (data) => {
console.log(data.toString());
});
grep.stderr.on('data', (data) => {
console.error(grep stderr: ${data});
});
grep.on('close', (code) => {
if (code !== 0) {
console.log(grep process exited with code ${code});
}
});
失敗したspawnを確認する例:
code:js
const { spawn } = require('child_process');
const subprocess = spawn('bad_command');
subprocess.on('error', (err) => {
console.error('Failed to start subprocess.');
});
一定のプラットフォーム(macOS、Linux)は他のOS(Windows、SunOS)がコマンドを使う間にプロセスタイトルのargv[0]の値を使う。
Node.jsはスタートアップ上でprocess.execPathによってargv[0]を上書きするので、Node.jsのchild processのprocess.argv[0]は親から出すために渡したargv0パラメータとマッチせず、代わりにprocess.argv0プロパティで取り出すこと。
options.detached
Windows上で、tureにoptions.detachedをセットすることはparent exitの後で起動し続けるのにchild processを可能にさせる。childはコンソールウィンドウを所有している。いったんchild processを友好にして、無効にさせることができない。
非Windowsプラットフォーム上で、もしoptions.detachedがtrueなら、child processは新しいプロセスグループとセッションのリーダーに作らせる。child processはdetachedかそうでないかにかかわらずparent exitの後に起動し続ける。詳しくはsetsid(2)を見ること。 デフォルトで、parentは終了するために切り離されたchildを待つ。終了するために与えられたsubprocessを待ってからのparentを防ぐために、suhprocess.unref()メソッドを使うこと。そうするためには、childとparentの間の出されたIPCチャネルがある限り、childを独立して終了するためにparentにさせるため、参照カウントでchildを含めるべきでないparentのイベントループを起こす。
長い起動プロセスを始めるためにdetachedオプションを使うときに、プロセスはparentに繋げないstdio設定を提供しない限りparent exitのあとにバックグラウンドで起動し続けない。もしparentのstdioが継承したなら、childは管理しているターミナルをつけ続ける。
切り離して無視されるparentstdioファイルディスクリプタによる、長い起動処理の例で、parentの終了を無視する:
code:js
const { spawn } = require('child_process');
detached: true,
stdio: 'ignore'
});
subprocess.unref();
代わりにファイルの中でchild process出力をリダイレクトできる:
code:js
const fs = require('fs');
const { spawn } = require('child_process');
const out = fs.openSync('./out.log', 'a');
const err = fs.openSync('./out.log', 'a');
const subprocess = spawn('prg', [], {
detached: true,
});
subprocess.unref();
options.stdio
options.stdioはparentとchild process間で出されたパイプを設定するために使われる。デフォルトで、childのstdin、stdout、stderrはChildProcessオブジェクト上のsubprocess.stdin、subprocess.stdout、subprocess.stderrストリームに対応するためにリダイレクトされる。これは['pipe', 'pipe', 'pipe']と等しいoptions.stdioをセットするのと同等。
便宜上、options.stdioは
For convenience, options.stdio may be one of the following strings:
Otherwise, the value of options.stdio is an array where each index corresponds to an fd in the child. The fds 0, 1, and 2 correspond to stdin, stdout, and stderr, respectively. Additional fds can be specified to create additional pipes between the parent and child. The value is one of the following:
'pipe': Create a pipe between the child process and the parent process. The parent end of the pipe is exposed to the parent as a property on the child_process object as subprocess.stdiofd. Pipes created for fds 0, 1, and 2 are also available as subprocess.stdin, subprocess.stdout and subprocess.stderr, respectively. 'ipc': Create an IPC channel for passing messages/file descriptors between parent and child. A ChildProcess may have at most one IPC stdio file descriptor. Setting this option enables the subprocess.send() method. If the child is a Node.js process, the presence of an IPC channel will enable process.send() and process.disconnect() methods, as well as 'disconnect' and 'message' events within the child.
Accessing the IPC channel fd in any way other than process.send() or using the IPC channel with a child process that is not a Node.js instance is not supported.
'ignore': Instructs Node.js to ignore the fd in the child. While Node.js will always open fds 0, 1, and 2 for the processes it spawns, setting the fd to 'ignore' will cause Node.js to open /dev/null and attach it to the child's fd.
'inherit': Pass through the corresponding stdio stream to/from the parent process. In the first three positions, this is equivalent to process.stdin, process.stdout, and process.stderr, respectively. In any other position, equivalent to 'ignore'.
<Stream> object: Share a readable or writable stream that refers to a tty, file, socket, or a pipe with the child process. The stream's underlying file descriptor is duplicated in the child process to the fd that corresponds to the index in the stdio array. The stream must have an underlying descriptor (file streams do not until the 'open' event has occurred).
Positive integer: The integer value is interpreted as a file descriptor that is currently open in the parent process. It is shared with the child process, similar to how <Stream> objects can be shared. Passing sockets is not supported on Windows.
null, undefined: Use default value. For stdio fds 0, 1, and 2 (in other words, stdin, stdout, and stderr) a pipe is created. For fd 3 and up, the default is 'ignore'.
const { spawn } = require('child_process');
// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });
// Spawn child sharing only stderr.
// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
It is worth noting that when an IPC channel is established between the parent and child processes, and the child is a Node.js process, the child is launched with the IPC channel unreferenced (using unref()) until the child registers an event handler for the 'disconnect' event or the 'message' event. This allows the child to exit normally without the process being held open by the open IPC channel.
On Unix-like operating systems, the child_process.spawn() method performs memory operations synchronously before decoupling the event loop from the child. Applications with a large memory footprint may find frequent child_process.spawn() calls to be a bottleneck. For more information, see V8 issue 7381.
See also: child_process.exec() and child_process.fork().