子プロセス#

安定性: 2 - Stable

ソースコード: lib/child_process.js

node:child_processモジュールは、popen(3)と似ていますが同一ではない方法で、サブプロセスを起動する機能を提供します。この機能は主にchild_process.spawn()関数によって提供されます。

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

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}`);
});import { spawn } from 'node:child_process';
const ls = spawn('ls', ['-lh', '/usr']);

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}`);
});

デフォルトでは、stdinstdoutstderrのためのパイプが、親Node.jsプロセスと起動されたサブプロセスの間に確立されます。これらのパイプは限定的(かつプラットフォーム固有)な容量を持ちます。サブプロセスが出力をキャプチャされることなくその制限を超えてstdoutに書き込むと、サブプロセスはパイプバッファがより多くのデータを受け入れるのを待ってブロックします。これはシェルにおけるパイプの挙動と同一です。出力が消費されない場合は、{ stdio: 'ignore' }オプションを使用してください。

コマンドの検索は、optionsオブジェクトにenvが含まれている場合、options.env.PATH環境変数を使用して実行されます。それ以外の場合は、process.env.PATHが使用されます。options.envPATHなしで設定された場合、Unixではデフォルトの検索パス/usr/bin:/binで検索が行われます(execvpe/execvpについてはお使いのオペレーティングシステムのマニュアルを参照してください)。Windowsでは、現在のプロセスの環境変数PATHが使用されます。

Windowsでは、環境変数は大文字と小文字を区別しません。Node.jsはenvのキーを辞書順にソートし、大文字と小文字を区別しないマッチングで最初に見つかったものを使用します。辞書順で最初のものだけがサブプロセスに渡されます。これにより、WindowsでPATHPathのように、同じキーの複数のバリアントを持つオブジェクトをenvオプションに渡すと問題が発生する可能性があります。

child_process.spawn()メソッドは、Node.jsのイベントループをブロックすることなく、非同期に子プロセスを起動します。child_process.spawnSync()関数は、起動されたプロセスが終了するか強制終了されるまでイベントループをブロックする同期的な方法で同等の機能を提供します。

便宜上、node:child_processモジュールは、child_process.spawn()child_process.spawnSync()に対するいくつかの同期的および非同期的な代替手段を提供します。これらの代替手段はそれぞれ、child_process.spawn()またはchild_process.spawnSync()の上に実装されています。

シェルスクリプトの自動化など、特定のユースケースでは、同期的な対応物の方が便利な場合があります。しかし、多くの場合、同期的なメソッドは、起動されたプロセスが完了する間イベントループを停止させるため、パフォーマンスに重大な影響を与える可能性があります。

非同期なプロセスの作成#

child_process.spawn()child_process.fork()child_process.exec()child_process.execFile()メソッドはすべて、他のNode.js APIに典型的な、慣用的な非同期プログラミングパターンに従います。

これらのメソッドはそれぞれChildProcessインスタンスを返します。これらのオブジェクトはNode.jsのEventEmitter APIを実装しており、親プロセスが子プロセスのライフサイクル中に特定のイベントが発生したときに呼び出されるリスナー関数を登録できます。

child_process.exec()およびchild_process.execFile()メソッドでは、子プロセスが終了したときに呼び出されるオプションのcallback関数を指定することもできます。

Windowsでの.batおよび.cmdファイルのを起動#

child_process.exec()child_process.execFile()の区別の重要性は、プラットフォームによって異なります。Unix系オペレーティングシステム(Unix、Linux、macOS)では、child_process.execFile()はデフォルトでシェルを起動しないため、より効率的です。しかし、Windowsでは.batおよび.cmdファイルはターミナルなしでは自己実行できないため、child_process.execFile()を使用して起動することはできません。Windowsで実行する場合、.batおよび.cmdファイルは、shellオプションを設定したchild_process.spawn()child_process.exec()、またはcmd.exeを起動して.bat.cmdファイルを引数として渡す(shellオプションとchild_process.exec()が行うことです)ことで呼び出すことができます。どの場合でも、スクリプトファイル名にスペースが含まれている場合は引用符で囲む必要があります。

// OR...
const { exec, spawn } = require('node: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) => {
  // ...
});// OR...
import { exec, spawn } from 'node: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 <string> 実行するコマンド。引数はスペースで区切られます。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。 デフォルト: process.cwd()
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • encoding <string> デフォルト: 'utf8'
    • shell <string> コマンドを実行するシェル。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: Unixでは'/bin/sh'、Windowsではprocess.env.ComSpec
    • signal <AbortSignal> AbortSignalを使用して子プロセスを中止できます。
    • timeout <number> デフォルト: 0
    • maxBuffer <number> stdoutまたはstderrで許可される最大のデータ量(バイト単位)。超過した場合、子プロセスは終了させられ、すべての出力は切り詰められます。maxBufferとUnicodeの注意点を参照してください。 デフォルト: 1024 * 1024
    • killSignal <string> | <integer> デフォルト: 'SIGTERM'
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
  • callback <Function> プロセスが終了したときに出力とともに呼び出されます。
  • 戻り値: <ChildProcess>

シェルを起動し、そのシェル内でcommandを実行し、生成された出力をバッファリングします。exec関数に渡されるcommand文字列はシェルによって直接処理されるため、特殊文字(シェルによって異なります)は適宜対処する必要があります。

const { exec } = require('node:child_process');

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.import { exec } from 'node:child_process';

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.

サニタイズされていないユーザー入力をこの関数に決して渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

callback関数が提供された場合、引数(error, stdout, stderr)で呼び出されます。成功した場合、errornullになります。エラーの場合、errorErrorのインスタンスになります。error.codeプロパティはプロセスの終了コードになります。慣例として、0以外の終了コードはエラーを示します。error.signalはプロセスを終了させたシグナルになります。

コールバックに渡されるstdoutstderr引数には、子プロセスの標準出力と標準エラー出力が含まれます。デフォルトでは、Node.jsは出力をUTF-8としてデコードし、文字列をコールバックに渡します。encodingオプションを使用して、stdoutとstderrの出力のデコードに使用する文字エンコーディングを指定できます。encoding'buffer'、または認識されない文字エンコーディングの場合、代わりにBufferオブジェクトがコールバックに渡されます。

const { exec } = require('node: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}`);
});import { exec } from 'node: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}`);
});

timeout0より大きい場合、子プロセスがtimeoutミリ秒より長く実行された場合、親プロセスはkillSignalプロパティで指定されたシグナル(デフォルトは'SIGTERM')を送信します。

exec(3) POSIXシステムコールとは異なり、child_process.exec()は既存のプロセスを置き換えせず、シェルを使用してコマンドを実行します。

このメソッドがutil.promisify()化されたバージョンとして呼び出された場合、stdoutstderrプロパティを持つObjectに対するPromiseを返します。返されたChildProcessインスタンスは、childプロパティとしてPromiseにアタッチされます。エラーの場合(0以外の終了コードになるエラーを含む)、拒否されたPromiseが返されます。これにはコールバックで与えられるのと同じerrorオブジェクトが含まれますが、stdoutstderrという2つの追加プロパティが付きます。

const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();import { promisify } from 'node:util';
import child_process from 'node:child_process';
const exec = promisify(child_process.exec);

async function lsExample() {
  const { stdout, stderr } = await exec('ls');
  console.log('stdout:', stdout);
  console.error('stderr:', stderr);
}
lsExample();

signalオプションが有効な場合、対応するAbortController.abort()を呼び出すことは、子プロセスで.kill()を呼び出すのと似ていますが、コールバックに渡されるエラーはAbortErrorになります。

const { exec } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();import { exec } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();

child_process.execFile(file[, args][, options][, callback])#

  • file <string> 実行する実行可能ファイルの名前またはパス。
  • args <string[]> 文字列引数のリスト。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • encoding <string> デフォルト: 'utf8'
    • timeout <number> デフォルト: 0
    • maxBuffer <number> stdoutまたはstderrで許可される最大のデータ量(バイト単位)。超過した場合、子プロセスは終了させられ、すべての出力は切り詰められます。maxBufferとUnicodeの注意点を参照してください。 デフォルト: 1024 * 1024
    • killSignal <string> | <integer> デフォルト: 'SIGTERM'
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
    • windowsVerbatimArguments <boolean> Windowsでは引数の引用符付けやエスケープは行われません。Unixでは無視されます。 デフォルト: false
    • shell <boolean> | <string> trueの場合、シェル内でcommandを実行します。Unixでは'/bin/sh'を使用し、Windowsではprocess.env.ComSpecを使用します。文字列として別のシェルを指定することもできます。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: false(シェルなし)。
    • signal <AbortSignal> AbortSignalを使用して子プロセスを中止できます。
  • callback <Function> プロセス終了時に出力と共に呼び出されます。
  • 戻り値: <ChildProcess>

child_process.execFile()関数はchild_process.exec()と似ていますが、デフォルトでシェルを起動しない点が異なります。代わりに、指定された実行可能ファイルfileが新しいプロセスとして直接起動されるため、child_process.exec()よりも若干効率的です。

child_process.exec()と同じオプションがサポートされています。シェルが起動されないため、I/Oリダイレクトやファイルグロビングのような動作はサポートされていません。

const { execFile } = require('node:child_process');
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
});import { execFile } from 'node:child_process';
const child = execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    throw error;
  }
  console.log(stdout);
});

コールバックに渡されるstdoutstderr引数には、子プロセスの標準出力と標準エラー出力が含まれます。デフォルトでは、Node.jsは出力をUTF-8としてデコードし、文字列をコールバックに渡します。encodingオプションを使用して、stdoutとstderrの出力のデコードに使用する文字エンコーディングを指定できます。encoding'buffer'、または認識されない文字エンコーディングの場合、代わりにBufferオブジェクトがコールバックに渡されます。

このメソッドがutil.promisify()化されたバージョンとして呼び出された場合、stdoutstderrプロパティを持つObjectに対するPromiseを返します。返されたChildProcessインスタンスは、childプロパティとしてPromiseにアタッチされます。エラーの場合(0以外の終了コードになるエラーを含む)、拒否されたPromiseが返されます。これにはコールバックで与えられるのと同じerrorオブジェクトが含まれますが、stdoutstderrという2つの追加プロパティが付きます。

const util = require('node:util');
const execFile = util.promisify(require('node:child_process').execFile);
async function getVersion() {
  const { stdout } = await execFile('node', ['--version']);
  console.log(stdout);
}
getVersion();import { promisify } from 'node:util';
import child_process from 'node:child_process';
const execFile = promisify(child_process.execFile);
async function getVersion() {
  const { stdout } = await execFile('node', ['--version']);
  console.log(stdout);
}
getVersion();

shellオプションが有効な場合、サニタイズされていないユーザー入力をこの関数に渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

signalオプションが有効な場合、対応するAbortController.abort()を呼び出すことは、子プロセスで.kill()を呼び出すのと似ていますが、コールバックに渡されるエラーはAbortErrorになります。

const { execFile } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const child = execFile('node', ['--version'], { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();import { execFile } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const child = execFile('node', ['--version'], { signal }, (error) => {
  console.error(error); // an AbortError
});
controller.abort();

child_process.fork(modulePath[, args][, options])#

  • modulePath <string> | <URL> 子プロセスで実行するモジュール。
  • args <string[]> 文字列引数のリスト。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • detached <boolean> 親プロセスから独立して実行するように子プロセスを準備します。具体的な動作はプラットフォームに依存します(options.detached参照)。
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • execPath <string> 子プロセスを作成するために使用される実行可能ファイル。
    • execArgv <string[]> 実行可能ファイルに渡される文字列引数のリスト。 デフォルト: process.execArgv
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • serialization <string> プロセス間でメッセージを送信する際に使用するシリアライゼーションの種類を指定します。可能な値は'json''advanced'です。詳細は高度なシリアライゼーションを参照してください。 デフォルト: 'json'
    • signal <AbortSignal> AbortSignalを使用して子プロセスを終了できます。
    • killSignal <string> | <integer> 起動されたプロセスがタイムアウトまたはアボートシグナルによってキルされる際に使用されるシグナル値。 デフォルト: 'SIGTERM'
    • silent <boolean> trueの場合、子プロセスのstdin、stdout、stderrは親プロセスにパイプされます。そうでない場合、それらは親プロセスから継承されます。詳細については、child_process.spawn()stdio'pipe'および'inherit'オプションを参照してください。 デフォルト: false
    • stdio <Array> | <string> child_process.spawn()stdioを参照してください。このオプションが提供されると、silentを上書きします。配列形式を使用する場合、値'ipc'を持つ項目を正確に1つ含める必要があり、そうでない場合はエラーがスローされます。例: [0, 1, 2, 'ipc']
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • windowsVerbatimArguments <boolean> Windowsでは引数の引用符付けやエスケープは行われません。Unixでは無視されます。 デフォルト: false
    • timeout <number> プロセスが実行を許可される最大時間(ミリ秒単位)。 デフォルト: undefined
  • 戻り値: <ChildProcess>

child_process.fork()メソッドは、特に新しいNode.jsプロセスを起動するために使用されるchild_process.spawn()の特殊なケースです。child_process.spawn()と同様に、ChildProcessオブジェクトが返されます。返されたChildProcessには、親と子の間でメッセージをやり取りできる追加の通信チャネルが組み込まれています。詳細はsubprocess.send()を参照してください。

起動されたNode.jsの子プロセスは、両者間に確立されたIPC通信チャネルを除いて、親から独立していることに注意してください。各プロセスは独自のメモリとV8インスタンスを持っています。追加のリソース割り当てが必要なため、多数の子Node.jsプロセスを起動することは推奨されません。

デフォルトでは、child_process.fork()は親プロセスのprocess.execPathを使用して新しいNode.jsインスタンスを起動します。optionsオブジェクトのexecPathプロパティにより、代替の実行パスを使用できます。

カスタムのexecPathで起動されたNode.jsプロセスは、子プロセスの環境変数NODE_CHANNEL_FDで識別されるファイルディスクリプタ(fd)を使用して親プロセスと通信します。

fork(2) POSIXシステムコールとは異なり、child_process.fork()は現在のプロセスを複製しません。

child_process.spawn()で利用可能なshellオプションはchild_process.fork()ではサポートされておらず、設定されても無視されます。

signalオプションが有効な場合、対応するAbortController.abort()を呼び出すことは、子プロセスで.kill()を呼び出すのと似ていますが、コールバックに渡されるエラーはAbortErrorになります。

const { fork } = require('node:child_process');
const process = require('node:process');

if (process.argv[2] === 'child') {
  setTimeout(() => {
    console.log(`Hello from ${process.argv[2]}!`);
  }, 1_000);
} else {
  const controller = new AbortController();
  const { signal } = controller;
  const child = fork(__filename, ['child'], { signal });
  child.on('error', (err) => {
    // This will be called with err being an AbortError if the controller aborts
  });
  controller.abort(); // Stops the child process
}import { fork } from 'node:child_process';
import process from 'node:process';

if (process.argv[2] === 'child') {
  setTimeout(() => {
    console.log(`Hello from ${process.argv[2]}!`);
  }, 1_000);
} else {
  const controller = new AbortController();
  const { signal } = controller;
  const child = fork(import.meta.url, ['child'], { signal });
  child.on('error', (err) => {
    // This will be called with err being an AbortError if the controller aborts
  });
  controller.abort(); // Stops the child process
}

child_process.spawn(command[, args][, options])#

  • command <string> 実行するコマンド。
  • args <string[]> 文字列引数のリスト。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • argv0 <string> 子プロセスに送信されるargv[0]の値を明示的に設定します。指定しない場合、commandに設定されます。
    • stdio <Array> | <string> 子の標準入出力設定(options.stdio参照)。
    • detached <boolean> 親プロセスから独立して実行するように子プロセスを準備します。具体的な動作はプラットフォームに依存します(options.detached参照)。
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • serialization <string> プロセス間でメッセージを送信する際に使用するシリアライゼーションの種類を指定します。可能な値は'json''advanced'です。詳細は高度なシリアライゼーションを参照してください。 デフォルト: 'json'
    • shell <boolean> | <string> trueの場合、シェル内でcommandを実行します。Unixでは'/bin/sh'を使用し、Windowsではprocess.env.ComSpecを使用します。文字列として別のシェルを指定することもできます。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: false(シェルなし)。
    • windowsVerbatimArguments <boolean> Windowsでは引数の引用符付けやエスケープは行われません。Unixでは無視されます。shellが指定され、それがCMDの場合、自動的にtrueに設定されます。 デフォルト: false
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
    • signal <AbortSignal> AbortSignalを使用して子プロセスを中止できます。
    • timeout <number> プロセスが実行を許可される最大時間(ミリ秒単位)。 デフォルト: undefined
    • killSignal <string> | <integer> 起動されたプロセスがタイムアウトまたはアボートシグナルによってキルされる際に使用されるシグナル値。 デフォルト: 'SIGTERM'
  • 戻り値: <ChildProcess>

child_process.spawn()メソッドは、指定されたcommandと、argsのコマンドライン引数を使用して新しいプロセスを起動します。省略された場合、argsは空の配列にデフォルト設定されます。

shellオプションが有効な場合、サニタイズされていないユーザー入力をこの関数に渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

3番目の引数は、追加のオプションを指定するために使用でき、以下のデフォルト値があります。

const defaults = {
  cwd: undefined,
  env: process.env,
}; 

cwdを使用して、プロセスが起動される作業ディレクトリを指定します。指定しない場合、デフォルトは現在の作業ディレクトリを継承することです。指定されたがパスが存在しない場合、子プロセスはENOENTエラーを発し、即座に終了します。コマンドが存在しない場合もENOENTが発行されます。

envを使用して、新しいプロセスから見える環境変数を指定します。デフォルトはprocess.envです。

env内のundefined値は無視されます。

ls -lh /usrを実行し、stdoutstderr、および終了コードをキャプチャする例:

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

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}`);
});import { spawn } from 'node:child_process';
const ls = spawn('ls', ['-lh', '/usr']);

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を実行するための非常に手の込んだ方法

const { spawn } = require('node: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}`);
  }
});import { spawn } from 'node: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を確認する例

const { spawn } = require('node:child_process');
const subprocess = spawn('bad_command');

subprocess.on('error', (err) => {
  console.error('Failed to start subprocess.');
});import { spawn } from 'node:child_process';
const subprocess = spawn('bad_command');

subprocess.on('error', (err) => {
  console.error('Failed to start subprocess.');
});

特定のプラットフォーム(macOS、Linux)はプロセス名にargv[0]の値を使用しますが、他のプラットフォーム(Windows、SunOS)はcommandを使用します。

Node.jsは起動時にargv[0]process.execPathで上書きするため、Node.jsの子プロセス内のprocess.argv[0]は、親からspawnに渡されたargv0パラメータと一致しません。代わりにprocess.argv0プロパティで取得してください。

signalオプションが有効な場合、対応するAbortController.abort()を呼び出すことは、子プロセスで.kill()を呼び出すのと似ていますが、コールバックに渡されるエラーはAbortErrorになります。

const { spawn } = require('node:child_process');
const controller = new AbortController();
const { signal } = controller;
const grep = spawn('grep', ['ssh'], { signal });
grep.on('error', (err) => {
  // This will be called with err being an AbortError if the controller aborts
});
controller.abort(); // Stops the child processimport { spawn } from 'node:child_process';
const controller = new AbortController();
const { signal } = controller;
const grep = spawn('grep', ['ssh'], { signal });
grep.on('error', (err) => {
  // This will be called with err being an AbortError if the controller aborts
});
controller.abort(); // Stops the child process
options.detached#

Windowsでは、options.detachedtrueに設定すると、親プロセスが終了した後も子プロセスが実行を続けることが可能になります。子プロセスは独自のコンソールウィンドウを持ちます。一度子プロセスで有効にすると、無効にすることはできません。

Windows以外のプラットフォームでは、options.detachedtrueに設定されている場合、子プロセスは新しいプロセスグループとセッションのリーダーになります。子プロセスは、分離されているかどうかに関わらず、親が終了した後も実行を続けることができます。詳細についてはsetsid(2)を参照してください。

デフォルトでは、親は分離された子プロセスが終了するのを待ちます。親プロセスが特定のsubprocessが終了するのを待たないようにするには、subprocess.unref()メソッドを使用します。そうすると、親プロセスのイベントループが子プロセスを参照カウントに含めなくなり、子と親の間に確立されたIPCチャネルがない限り、親プロセスは子プロセスとは独立して終了できるようになります。

detachedオプションを使用して長時間実行プロセスを開始する場合、親に接続されていないstdio設定が提供されない限り、親が終了した後にプロセスはバックグラウンドで実行され続けないでしょう。親プロセスのstdioが継承される場合、子プロセスは制御端末に接続されたままになります。

長時間実行プロセスの例。親の終了を無視するために、分離し、親のstdioファイルディスクリプタも無視します。

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();

あるいは、子プロセスの出力をファイルにリダイレクトすることもできます。

const { openSync } = require('node:fs');
const { spawn } = require('node:child_process');
const out = openSync('./out.log', 'a');
const err = openSync('./out.log', 'a');

const subprocess = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ],
});

subprocess.unref();import { openSync } from 'node:fs';
import { spawn } from 'node:child_process';
const out = openSync('./out.log', 'a');
const err = openSync('./out.log', 'a');

const subprocess = spawn('prg', [], {
  detached: true,
  stdio: [ 'ignore', out, err ],
});

subprocess.unref();
options.stdio#

options.stdioオプションは、親と子のプロセス間に確立されるパイプを設定するために使用されます。デフォルトでは、子のstdin、stdout、およびstderrは、ChildProcessオブジェクト上の対応するsubprocess.stdinsubprocess.stdout、およびsubprocess.stderrストリームにリダイレクトされます。これはoptions.stdio['pipe', 'pipe', 'pipe']に設定するのと同じです。

便宜上、options.stdioは以下の文字列のいずれかになります。

  • 'pipe': ['pipe', 'pipe', 'pipe']と同等(デフォルト)
  • 'overlapped': ['overlapped', 'overlapped', 'overlapped']と同等
  • 'ignore': ['ignore', 'ignore', 'ignore']と同等
  • 'inherit': ['inherit', 'inherit', 'inherit']または[0, 1, 2]と同等

それ以外の場合、options.stdioの値は配列で、各インデックスが子のfdに対応します。fd 0、1、2はそれぞれstdin、stdout、stderrに対応します。追加のfdを指定して、親と子の間に追加のパイプを作成できます。値は以下のいずれかです。

  1. 'pipe': 子プロセスと親プロセスの間にパイプを作成します。パイプの親側は、child_processオブジェクトのプロパティとしてsubprocess.stdio[fd]として親に公開されます。fd 0、1、2用に作成されたパイプは、それぞれsubprocess.stdinsubprocess.stdoutsubprocess.stderrとしても利用可能です。これらは実際のUnixパイプではないため、子プロセスは/dev/fd/2/dev/stdoutのようなディスクリプタファイルでそれらを使用することはできません。

  2. 'overlapped': 'pipe'と同じですが、ハンドルにFILE_FLAG_OVERLAPPEDフラグが設定されます。これは、子プロセスのstdioハンドルでのオーバーラップI/Oに必要です。詳細はドキュメントを参照してください。これはWindows以外のシステムでは'pipe'と全く同じです。

  3. 'ipc': 親と子の間でメッセージやファイルディスクリプタを渡すためのIPCチャネルを作成します。ChildProcessは最大で1つのIPC stdioファイルディスクリプタを持つことができます。このオプションを設定するとsubprocess.send()メソッドが有効になります。子プロセスがNode.jsインスタンスの場合、IPCチャネルの存在により、子プロセス内でprocess.send()process.disconnect()メソッド、および'disconnect''message'イベントが有効になります。

    process.send()以外の方法でIPCチャネルfdにアクセスしたり、Node.jsインスタンスではない子プロセスでIPCチャネルを使用したりすることはサポートされていません。

  4. 'ignore': Node.jsに子のfdを無視するよう指示します。Node.jsは常に起動するプロセスのためにfd 0、1、2を開きますが、fdを'ignore'に設定すると、Node.jsは/dev/nullを開き、それを子のfdにアタッチします。

  5. 'inherit': 対応するstdioストリームを親プロセスとの間で受け渡します。最初の3つの位置では、これはそれぞれprocess.stdinprocess.stdoutprocess.stderrと同等です。他の位置では'ignore'と同等です。

  6. <Stream>オブジェクト: tty、ファイル、ソケット、またはパイプを参照する読み取り可能または書き込み可能なストリームを子プロセスと共有します。ストリームの基になるファイルディスクリプタは、stdio配列のインデックスに対応するfdに子プロセスで複製されます。ストリームは基になるディスクリプタを持っている必要があります(ファイルストリームは'open'イベントが発生するまで開始されません)。 注: 技術的にはstdinを書き込み可能として、stdout/stderrを読み取り可能として渡すことは可能ですが、推奨されません。読み取り可能ストリームと書き込み可能ストリームは異なる動作をするように設計されており、それらを不適切に使用する(例:書き込み可能ストリームが期待される場所に読み取り可能ストリームを渡す)と、予期せぬ結果やエラーにつながる可能性があります。この方法は、ストリームがエラーに遭遇した場合に未定義の動作やコールバックの脱落を引き起こす可能性があるため、推奨されません。親と子のプロセス間の意図したデータフローを維持するために、常にstdinは読み取り可能として、stdout/stderrは書き込み可能として使用するようにしてください。

  7. 正の整数: 整数値は、親プロセスで開かれているファイルディスクリプタとして解釈されます。<Stream>オブジェクトを共有できるのと同様に、子プロセスと共有されます。Windowsではソケットの受け渡しはサポートされていません。

  8. null, undefined: デフォルト値を使用します。stdio fd 0, 1, 2(つまり、stdin, stdout, stderr)にはパイプが作成されます。fd 3以上では、デフォルトは'ignore'です。

const { spawn } = require('node:child_process');
const process = require('node:process');

// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr.
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });import { spawn } from 'node:child_process';
import process from 'node:process';

// Child will use parent's stdios.
spawn('prg', [], { stdio: 'inherit' });

// Spawn child sharing only stderr.
spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] });

// Open an extra fd=4, to interact with programs presenting a
// startd-style interface.
spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });

親と子のプロセス間にIPCチャネルが確立され、子プロセスがNode.jsインスタンスである場合、子プロセスは、子プロセスが'disconnect'イベントまたは'message'イベントのイベントハンドラを登録するまで、IPCチャネルが参照されていない状態で(unref()を使用して)起動されることは注目に値します。これにより、開いているIPCチャネルによってプロセスが開いたままになることなく、子プロセスが正常に終了できます。 参照: child_process.exec() および child_process.fork()

同期的なプロセスの作成#

child_process.spawnSync()child_process.execSync()child_process.execFileSync()メソッドは同期的であり、Node.jsのイベントループをブロックし、起動されたプロセスが終了するまで追加のコードの実行を一時停止します。

このようなブロッキングコールは、主に汎用的なスクリプトタスクを簡素化するためや、起動時のアプリケーション設定の読み込み/処理を簡素化するために役立ちます。

child_process.execFileSync(file[, args][, options])#

  • file <string> 実行する実行可能ファイルの名前またはパス。
  • args <string[]> 文字列引数のリスト。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 起動されたプロセスにstdinとして渡される値。stdio[0]'pipe'に設定されている場合、この値を指定するとstdio[0]が上書きされます。
    • stdio <string> | <Array> 子の標準入出力設定。child_process.spawn()stdioを参照してください。stdioが指定されない限り、stderrはデフォルトで親プロセスのstderrに出力されます。 デフォルト: 'pipe'
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • timeout <number> プロセスが実行を許可される最大時間(ミリ秒単位)。 デフォルト: undefined
    • killSignal <string> | <integer> 起動されたプロセスがキルされる際に使用されるシグナル値。 デフォルト: 'SIGTERM'
    • maxBuffer <number> stdoutまたはstderrで許可される最大のデータ量(バイト単位)。超過した場合、子プロセスは終了させられます。maxBufferとUnicodeの注意点を参照してください。 デフォルト: 1024 * 1024
    • encoding <string> すべてのstdio入出力に使用されるエンコーディング。 デフォルト: 'buffer'
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
    • shell <boolean> | <string> trueの場合、シェル内でcommandを実行します。Unixでは'/bin/sh'を使用し、Windowsではprocess.env.ComSpecを使用します。文字列として別のシェルを指定することもできます。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: false(シェルなし)。
  • 戻り値: <Buffer> | <string> コマンドからの標準出力。

child_process.execFileSync()メソッドは、メソッドが子プロセスが完全に閉じるまで戻らないという点を除いて、一般的にchild_process.execFile()と同一です。タイムアウトが発生し、killSignalが送信された場合、メソッドはプロセスが完全に終了するまで戻りません。

子プロセスがSIGTERMシグナルを捕捉して処理し、終了しない場合でも、親プロセスは子プロセスが終了するまで待ち続けます。

プロセスがタイムアウトするか、ゼロ以外の終了コードを持つ場合、このメソッドは、基になるchild_process.spawnSync()の完全な結果を含むErrorをスローします。

shellオプションが有効な場合、サニタイズされていないユーザー入力をこの関数に渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

const { execFileSync } = require('node:child_process');

try {
  const stdout = execFileSync('my-script.sh', ['my-arg'], {
    // Capture stdout and stderr from child process. Overrides the
    // default behavior of streaming child stderr to the parent stderr
    stdio: 'pipe',

    // Use utf8 encoding for stdio pipes
    encoding: 'utf8',
  });

  console.log(stdout);
} catch (err) {
  if (err.code) {
    // Spawning child process failed
    console.error(err.code);
  } else {
    // Child was spawned but exited with non-zero exit code
    // Error contains any stdout and stderr from the child
    const { stdout, stderr } = err;

    console.error({ stdout, stderr });
  }
}import { execFileSync } from 'node:child_process';

try {
  const stdout = execFileSync('my-script.sh', ['my-arg'], {
    // Capture stdout and stderr from child process. Overrides the
    // default behavior of streaming child stderr to the parent stderr
    stdio: 'pipe',

    // Use utf8 encoding for stdio pipes
    encoding: 'utf8',
  });

  console.log(stdout);
} catch (err) {
  if (err.code) {
    // Spawning child process failed
    console.error(err.code);
  } else {
    // Child was spawned but exited with non-zero exit code
    // Error contains any stdout and stderr from the child
    const { stdout, stderr } = err;

    console.error({ stdout, stderr });
  }
}

child_process.execSync(command[, options])#

  • command <string> 実行するコマンド。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 起動されたプロセスにstdinとして渡される値。stdio[0]'pipe'に設定されている場合、この値を指定するとstdio[0]が上書きされます。
    • stdio <string> | <Array> 子の標準入出力設定。child_process.spawn()stdioを参照してください。stdioが指定されない限り、stderrはデフォルトで親プロセスのstderrに出力されます。 デフォルト: 'pipe'
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • shell <string> コマンドを実行するシェル。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: Unixでは'/bin/sh'、Windowsではprocess.env.ComSpec
    • uid <number> プロセスのユーザーIDを設定します。(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します。(setgid(2)参照)。
    • timeout <number> プロセスが実行を許可される最大時間(ミリ秒単位)。 デフォルト: undefined
    • killSignal <string> | <integer> 起動されたプロセスがキルされる際に使用されるシグナル値。 デフォルト: 'SIGTERM'
    • maxBuffer <number> stdoutまたはstderrで許可される最大のデータ量(バイト単位)。超過した場合、子プロセスは終了させられ、すべての出力は切り詰められます。maxBufferとUnicodeの注意点を参照してください。 デフォルト: 1024 * 1024
    • encoding <string> すべてのstdio入出力に使用されるエンコーディング。 デフォルト: 'buffer'
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
  • 戻り値: <Buffer> | <string> コマンドからの標準出力。

child_process.execSync()メソッドは、メソッドが子プロセスが完全に閉じるまで戻らないという点を除いて、一般的にchild_process.exec()と同一です。タイムアウトが発生してkillSignalが送信された場合、メソッドはプロセスが完全に終了するまで戻りません。子プロセスがSIGTERMシグナルを捕捉して処理し、終了しない場合でも、親プロセスは子プロセスが終了するまで待ち続けます。

プロセスがタイムアウトするか、ゼロ以外の終了コードを持つ場合、このメソッドは例外をスローします。Errorオブジェクトには、child_process.spawnSync()からの完全な結果が含まれます。

サニタイズされていないユーザー入力をこの関数に決して渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

child_process.spawnSync(command[, args][, options])#

  • command <string> 実行するコマンド。
  • args <string[]> 文字列引数のリスト。
  • options <Object>
    • cwd <string> | <URL> 子プロセスの現在の作業ディレクトリ。
    • input <string> | <Buffer> | <TypedArray> | <DataView> 起動されたプロセスにstdinとして渡される値。stdio[0]'pipe'に設定されている場合、この値を指定するとstdio[0]が上書きされます。
    • argv0 <string> 子プロセスに送信されるargv[0]の値を明示的に設定します。指定しない場合、commandに設定されます。
    • stdio <string> | <Array> 子の標準入出力設定。child_process.spawn()stdioを参照してください。 デフォルト: 'pipe'
    • env <Object> 環境変数のキーと値のペア。 デフォルト: process.env
    • uid <number> プロセスのユーザーIDを設定します(setuid(2)参照)。
    • gid <number> プロセスのグループIDを設定します(setgid(2)参照)。
    • timeout <number> プロセスが実行を許可される最大時間(ミリ秒単位)。 デフォルト: undefined
    • killSignal <string> | <integer> 起動されたプロセスがキルされる際に使用されるシグナル値。 デフォルト: 'SIGTERM'
    • maxBuffer <number> stdoutまたはstderrで許可される最大のデータ量(バイト単位)。超過した場合、子プロセスは終了させられ、すべての出力は切り詰められます。maxBufferとUnicodeの注意点を参照してください。 デフォルト: 1024 * 1024
    • encoding <string> すべてのstdio入出力に使用されるエンコーディング。 デフォルト: 'buffer'
    • shell <boolean> | <string> trueの場合、シェル内でcommandを実行します。Unixでは'/bin/sh'を使用し、Windowsではprocess.env.ComSpecを使用します。文字列として別のシェルを指定することもできます。シェルの要件およびデフォルトのWindowsシェルを参照してください。 デフォルト: false(シェルなし)。
    • windowsVerbatimArguments <boolean> Windowsでは引数の引用符付けやエスケープは行われません。Unixでは無視されます。shellが指定され、それがCMDの場合、自動的にtrueに設定されます。 デフォルト: false
    • windowsHide <boolean> Windowsシステムで通常作成されるサブプロセスのコンソールウィンドウを非表示にします。 デフォルト: false
  • 戻り値: <Object>
    • pid <number> 子プロセスのPID。
    • output <Array> stdio出力からの結果の配列。
    • stdout <Buffer> | <string> output[1]の内容。
    • stderr <Buffer> | <string> output[2]の内容。
    • status <number> | <null> サブプロセスの終了コード、またはサブプロセスがシグナルにより終了した場合はnull
    • signal <string> | <null> サブプロセスをキルするために使用されたシグナル、またはサブプロセスがシグナルにより終了しなかった場合はnull
    • error <Error> 子プロセスが失敗したかタイムアウトした場合のエラーオブジェクト。

child_process.spawnSync()メソッドは、関数が子プロセスが完全に閉じるまで戻らないという点を除いて、一般的にchild_process.spawn()と同一です。タイムアウトが発生してkillSignalが送信された場合、メソッドはプロセスが完全に終了するまで戻りません。プロセスがSIGTERMシグナルを捕捉して処理し、終了しない場合でも、親プロセスは子プロセスが終了するまで待ち続けます。

shellオプションが有効な場合、サニタイズされていないユーザー入力をこの関数に渡さないでください。シェルメタ文字を含む入力は、任意のコマンド実行をトリガーするために使用される可能性があります。

クラス: ChildProcess#

ChildProcessのインスタンスは、起動された子プロセスを表します。

ChildProcessのインスタンスは直接作成されることを意図していません。代わりに、child_process.spawn()child_process.exec()child_process.execFile()、またはchild_process.fork()メソッドを使用してChildProcessのインスタンスを作成してください。

イベント: 'close'#

  • code <number> 子プロセスが自ら終了した場合の終了コード、または子プロセスがシグナルにより終了した場合はnull
  • signal <string> 子プロセスが終了させられたシグナル、または子プロセスがシグナルにより終了しなかった場合はnull

'close'イベントは、プロセスが終了し、かつ子プロセスのstdioストリームが閉じられた後に発行されます。これは'exit'イベントとは異なります。なぜなら、複数のプロセスが同じstdioストリームを共有する可能性があるからです。'close'イベントは、'exit'が既に発行された後、または子プロセスの起動に失敗した場合は'error'の後に常に発行されます。

プロセスが終了した場合、codeはプロセスの最終的な終了コードで、それ以外はnullです。プロセスがシグナルの受信により終了した場合、signalはシグナルの文字列名で、それ以外はnullです。2つのうちどちらかは常に非nullです。

const { spawn } = require('node:child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process close all stdio with code ${code}`);
});

ls.on('exit', (code) => {
  console.log(`child process exited with code ${code}`);
});import { spawn } from 'node:child_process';
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process close all stdio with code ${code}`);
});

ls.on('exit', (code) => {
  console.log(`child process exited with code ${code}`);
});

イベント: 'disconnect'#

'disconnect'イベントは、親プロセスでsubprocess.disconnect()メソッドを呼び出した後、または子プロセスでprocess.disconnect()を呼び出した後に発行されます。切断後はメッセージの送受信ができなくなり、subprocess.connectedプロパティはfalseになります。

イベント: 'error'#

'error'イベントは以下の場合に発行されます:

  • プロセスを起動できなかった。
  • プロセスをキルできなかった。
  • 子プロセスへのメッセージ送信に失敗した。
  • signalオプションによって子プロセスが中止された。

エラーが発生した後、'exit'イベントは発行される場合とされない場合があります。'exit''error'の両方のイベントをリッスンする場合、誤ってハンドラ関数を複数回呼び出さないように注意してください。

subprocess.kill()およびsubprocess.send()も参照してください。

イベント: 'exit'#

  • code <number> 子プロセスが自ら終了した場合の終了コード、または子プロセスがシグナルにより終了した場合はnull
  • signal <string> 子プロセスが終了させられたシグナル、または子プロセスがシグナルにより終了しなかった場合はnull

'exit'イベントは、子プロセスが終了した後に発行されます。プロセスが終了した場合、codeはプロセスの最終的な終了コードで、それ以外はnullです。プロセスがシグナルの受信により終了した場合、signalはシグナルの文字列名で、それ以外はnullです。2つのうちどちらかは常に非nullです。

'exit'イベントがトリガーされたとき、子プロセスのstdioストリームはまだ開いている可能性があります。

Node.jsはSIGINTSIGTERMのシグナルハンドラを確立し、Node.jsプロセスはこれらのシグナルを受信してもすぐには終了しません。代わりに、Node.jsは一連のクリーンアップアクションを実行し、その後、処理されたシグナルを再発生させます。

waitpid(2)を参照してください。

イベント: 'message'#

'message'イベントは、子プロセスがprocess.send()を使用してメッセージを送信したときにトリガーされます。

メッセージはシリアライゼーションとパースを経ます。結果のメッセージは、元々送信されたものと同じではないかもしれません。

子プロセスを起動する際にserializationオプションが'advanced'に設定されていた場合、message引数にはJSONが表現できないデータが含まれることがあります。詳細は高度なシリアライゼーションを参照してください。

イベント: 'spawn'#

'spawn'イベントは、子プロセスが正常に起動した後に一度発行されます。子プロセスが正常に起動しない場合、'spawn'イベントは発行されず、代わりに'error'イベントが発行されます。

発行された場合、'spawn'イベントは他のすべてのイベントの前、およびstdoutまたはstderr経由でデータが受信される前に発生します。

'spawn'イベントは、起動されたプロセス内でエラーが発生するかどうかに関わらず発行されます。たとえば、bash some-commandが正常に起動した場合、bashsome-commandの起動に失敗したとしても、'spawn'イベントは発行されます。この注意点は{ shell: true }を使用する場合にも当てはまります。

subprocess.channel#

  • 型: <Object> 子プロセスへのIPCチャネルを表すパイプ。

subprocess.channelプロパティは、子のIPCチャネルへの参照です。IPCチャネルが存在しない場合、このプロパティはundefinedです。

subprocess.channel.ref()#

このメソッドは、事前に.unref()が呼び出されていた場合に、IPCチャネルが親プロセスのイベントループを実行し続けるようにします。

subprocess.channel.unref()#

このメソッドは、IPCチャネルが親プロセスのイベントループを実行し続けないようにし、チャネルが開いている間でも終了できるようにします。

subprocess.connected#

  • 型: <boolean> subprocess.disconnect()が呼び出された後にfalseに設定されます。

subprocess.connectedプロパティは、子プロセスからメッセージを送受信することがまだ可能かどうかを示します。subprocess.connectedfalseの場合、メッセージの送受信はできなくなります。

subprocess.disconnect()#

親と子のプロセス間のIPCチャネルを閉じ、他に子プロセスを生かし続ける接続がない場合に、子プロセスが正常に終了できるようにします。このメソッドを呼び出した後、親と子プロセス(それぞれ)のsubprocess.connectedprocess.connectedプロパティはfalseに設定され、プロセス間でメッセージを渡すことはできなくなります。

'disconnect'イベントは、受信中のメッセージがないときに発行されます。これは、ほとんどの場合、subprocess.disconnect()を呼び出した直後にトリガーされます。

子プロセスがNode.jsインスタンスである場合(例: child_process.fork()を使用して起動された場合)、子プロセス内でprocess.disconnect()メソッドを呼び出してIPCチャネルを閉じることもできます。

subprocess.exitCode#

subprocess.exitCodeプロパティは、子プロセスの終了コードを示します。子プロセスがまだ実行中の場合、このフィールドはnullになります。

subprocess.kill([signal])#

subprocess.kill()メソッドは、子プロセスにシグナルを送信します。引数が指定されない場合、プロセスには'SIGTERM'シグナルが送信されます。利用可能なシグナルのリストについてはsignal(7)を参照してください。この関数はkill(2)が成功した場合はtrueを、そうでなければfalseを返します。

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP');import { spawn } from 'node:child_process';
const grep = spawn('grep', ['ssh']);

grep.on('close', (code, signal) => {
  console.log(
    `child process terminated due to receipt of signal ${signal}`);
});

// Send SIGHUP to process.
grep.kill('SIGHUP');

シグナルが配送できない場合、ChildProcessオブジェクトは'error'イベントを発行することがあります。既に終了した子プロセスにシグナルを送信することはエラーではありませんが、予期せぬ結果を招く可能性があります。具体的には、プロセス識別子(PID)が別のプロセスに再割り当てされている場合、シグナルはそのプロセスに配送され、予期しない結果につながる可能性があります。

この関数名はkillですが、子プロセスに配送されるシグナルが実際にプロセスを終了させるとは限りません。

参考としてkill(2)を参照してください。

POSIXシグナルが存在しないWindowsでは、signal引数は'SIGKILL''SIGTERM''SIGINT''SIGQUIT'を除いて無視され、プロセスは常に強制的にかつ突然('SIGKILL'と同様に)キルされます。詳細はシグナルイベントを参照してください。

Linuxでは、親プロセスをキルしようとしても、その子プロセスの子プロセスは終了しません。これは、シェルで新しいプロセスを実行したり、ChildProcessshellオプションを使用した場合に起こり得ます。

const { spawn } = require('node:child_process');

const subprocess = spawn(
  'sh',
  [
    '-c',
    `node -e "setInterval(() => {
      console.log(process.pid, 'is alive')
    }, 500);"`,
  ], {
    stdio: ['inherit', 'inherit', 'inherit'],
  },
);

setTimeout(() => {
  subprocess.kill(); // Does not terminate the Node.js process in the shell.
}, 2000);import { spawn } from 'node:child_process';

const subprocess = spawn(
  'sh',
  [
    '-c',
    `node -e "setInterval(() => {
      console.log(process.pid, 'is alive')
    }, 500);"`,
  ], {
    stdio: ['inherit', 'inherit', 'inherit'],
  },
);

setTimeout(() => {
  subprocess.kill(); // Does not terminate the Node.js process in the shell.
}, 2000);

subprocess[Symbol.dispose]()#

subprocess.kill()'SIGTERM'で呼び出します。

subprocess.killed#

  • 型: <boolean> subprocess.kill()を使用して子プロセスにシグナルを正常に送信した後にtrueに設定されます。

subprocess.killedプロパティは、子プロセスがsubprocess.kill()からシグナルを正常に受信したかどうかを示します。killedプロパティは、子プロセスが終了したことを示すものではありません。

subprocess.pid#

子プロセスのプロセス識別子(PID)を返します。エラーにより子プロセスが起動に失敗した場合、値はundefinedとなり、errorが発行されます。

const { spawn } = require('node:child_process');
const grep = spawn('grep', ['ssh']);

console.log(`Spawned child pid: ${grep.pid}`);
grep.stdin.end();import { spawn } from 'node:child_process';
const grep = spawn('grep', ['ssh']);

console.log(`Spawned child pid: ${grep.pid}`);
grep.stdin.end();

subprocess.ref()#

subprocess.unref()を呼び出した後にsubprocess.ref()を呼び出すと、子プロセスの削除された参照カウントが復元され、親プロセスは自身が終了する前に子プロセスが終了するのを待つようになります。

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();
subprocess.ref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();
subprocess.ref();

subprocess.send(message[, sendHandle[, options]][, callback])#

  • message <Object>
  • sendHandle <Handle> | <undefined> undefined、またはnet.Socketnet.Server、またはdgram.Socketオブジェクト。
  • options <Object> options引数が存在する場合、それは特定の種類のハンドルの送信をパラメータ化するために使用されるオブジェクトです。optionsは以下のプロパティをサポートします:
    • keepOpen <boolean> net.Socketのインスタンスを渡す際に使用できる値。trueの場合、ソケットは送信プロセスで開いたままになります。 デフォルト: false
  • callback <Function>
  • 戻り値: <boolean>

親と子のプロセス間にIPCチャネルが確立されている場合(例: child_process.fork()を使用している場合)、subprocess.send()メソッドを使用して子プロセスにメッセージを送信できます。子プロセスがNode.jsインスタンスの場合、これらのメッセージは'message'イベントを介して受信できます。

メッセージはシリアライゼーションとパースを経ます。結果のメッセージは、元々送信されたものと同じではないかもしれません。

例えば、親スクリプトでは:

const { fork } = require('node:child_process');
const forkedProcess = fork(`${__dirname}/sub.js`);

forkedProcess.on('message', (message) => {
  console.log('PARENT got message:', message);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
forkedProcess.send({ hello: 'world' });import { fork } from 'node:child_process';
const forkedProcess = fork(`${import.meta.dirname}/sub.js`);

forkedProcess.on('message', (message) => {
  console.log('PARENT got message:', message);
});

// Causes the child to print: CHILD got message: { hello: 'world' }
forkedProcess.send({ hello: 'world' });

そして子スクリプト'sub.js'は次のようになります:

process.on('message', (message) => {
  console.log('CHILD got message:', message);
});

// Causes the parent to print: PARENT got message: { foo: 'bar', baz: null }
process.send({ foo: 'bar', baz: NaN }); 

子Node.jsプロセスは、子プロセスが親プロセスにメッセージを送り返すことができる独自のprocess.send()メソッドを持ちます。

{cmd: 'NODE_foo'}メッセージを送信する際には特別なケースがあります。cmdプロパティにNODE_プレフィックスを含むメッセージは、Node.jsコア内で使用するために予約されており、子の'message'イベントでは発行されません。むしろ、そのようなメッセージは'internalMessage'イベントを使用して発行され、Node.jsによって内部的に消費されます。アプリケーションは、予告なく変更される可能性があるため、そのようなメッセージの使用や'internalMessage'イベントのリッスンを避けるべきです。

subprocess.send()に渡すことができるオプションのsendHandle引数は、TCPサーバーまたはソケットオブジェクトを子プロセスに渡すためのものです。子プロセスは、'message'イベントに登録されたコールバック関数に渡される2番目の引数としてオブジェクトを受け取ります。ソケットで受信されバッファリングされたデータは子に送信されません。WindowsではIPCソケットの送信はサポートされていません。

オプションのcallbackは、メッセージが送信された後、しかし子プロセスがそれを受信する前に呼び出される関数です。この関数は単一の引数で呼び出されます:成功した場合はnull、失敗した場合はErrorオブジェクトです。

callback関数が提供されず、メッセージが送信できない場合、ChildProcessオブジェクトによって'error'イベントが発行されます。これは、例えば子プロセスが既に終了している場合に発生する可能性があります。

subprocess.send()は、チャネルが閉じているか、未送信メッセージのバックログがそれ以上送信するのが賢明でないしきい値を超えている場合にfalseを返します。それ以外の場合、メソッドはtrueを返します。callback関数を使用してフロー制御を実装できます。

例: サーバーオブジェクトの送信#

sendHandle引数は、例えば、以下の例のようにTCPサーバーオブジェクトのハンドルを子プロセスに渡すために使用できます。

const { fork } = require('node:child_process');
const { createServer } = require('node:net');

const subprocess = fork('subprocess.js');

// Open up the server object and send the handle.
const server = createServer();
server.on('connection', (socket) => {
  socket.end('handled by parent');
});
server.listen(1337, () => {
  subprocess.send('server', server);
});import { fork } from 'node:child_process';
import { createServer } from 'node:net';

const subprocess = fork('subprocess.js');

// Open up the server object and send the handle.
const server = createServer();
server.on('connection', (socket) => {
  socket.end('handled by parent');
});
server.listen(1337, () => {
  subprocess.send('server', server);
});

子プロセスはサーバーオブジェクトを次のように受け取ります:

process.on('message', (m, server) => {
  if (m === 'server') {
    server.on('connection', (socket) => {
      socket.end('handled by child');
    });
  }
}); 

サーバーが親と子の間で共有されると、一部の接続は親が、一部は子が処理できます。

上記の例ではnode:netモジュールを使用して作成されたサーバーを使用していますが、node:dgramモジュールのサーバーは、'connection'の代わりに'message'イベントをリッスンし、server.listen()の代わりにserver.bind()を使用する点を除いて、全く同じワークフローを使用します。ただし、これはUnixプラットフォームでのみサポートされています。

例: ソケットオブジェクトの送信#

同様に、sendHandler引数を使用してソケットのハンドルを子プロセスに渡すことができます。以下の例では、「通常」または「特別」な優先順位で接続を処理する2つの子を起動します。

const { fork } = require('node:child_process');
const { createServer } = require('node:net');

const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Open up the server and send sockets to child. Use pauseOnConnect to prevent
// the sockets from being read before they are sent to the child process.
const server = createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

  // If this is special priority...
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // This is normal priority.
  normal.send('socket', socket);
});
server.listen(1337);import { fork } from 'node:child_process';
import { createServer } from 'node:net';

const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

// Open up the server and send sockets to child. Use pauseOnConnect to prevent
// the sockets from being read before they are sent to the child process.
const server = createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

  // If this is special priority...
  if (socket.remoteAddress === '74.125.127.100') {
    special.send('socket', socket);
    return;
  }
  // This is normal priority.
  normal.send('socket', socket);
});
server.listen(1337);

subprocess.jsは、イベントコールバック関数に渡される2番目の引数としてソケットハンドルを受け取ります:

process.on('message', (m, socket) => {
  if (m === 'socket') {
    if (socket) {
      // Check that the client socket exists.
      // It is possible for the socket to be closed between the time it is
      // sent and the time it is received in the child process.
      socket.end(`Request handled with ${process.argv[2]} priority`);
    }
  }
}); 

サブプロセスに渡されたソケットで.maxConnectionsを使用しないでください。親はソケットがいつ破棄されたかを追跡できません。

サブプロセス内の'message'ハンドラは、接続が子に送信されるまでの間に閉じられている可能性があるため、socketが存在することを確認する必要があります。

subprocess.signalCode#

subprocess.signalCodeプロパティは、子プロセスが受信したシグナルを示します。もしあれば、なければnullです。

subprocess.spawnargs#

subprocess.spawnargsプロパティは、子プロセスが起動された際の完全なコマンドライン引数のリストを表します。

subprocess.spawnfile#

subprocess.spawnfileプロパティは、起動された子プロセスの実行可能ファイル名を示します。

child_process.fork()の場合、その値はprocess.execPathと等しくなります。child_process.spawn()の場合、その値は実行可能ファイルの名前になります。child_process.exec()の場合、その値は子プロセスが起動されたシェルの名前になります。

subprocess.stderr#

子プロセスの stderr を表す Readable Stream です。

子プロセスが stdio[2]'pipe' 以外に設定して生成された場合、これは null になります。

subprocess.stderrsubprocess.stdio[2] のエイリアスです。両方のプロパティは同じ値を参照します。

子プロセスの生成に成功しなかった場合、subprocess.stderr プロパティは null または undefined になることがあります。

subprocess.stdin#

子プロセスの stdin を表す Writable Stream です。

子プロセスがすべての入力を読み込むのを待つ場合、このストリームが end() によって閉じられるまで子プロセスは続行しません。

子プロセスが stdio[0]'pipe' 以外に設定して生成された場合、これは null になります。

subprocess.stdinsubprocess.stdio[0] のエイリアスです。両方のプロパティは同じ値を参照します。

子プロセスの生成に成功しなかった場合、subprocess.stdin プロパティは null または undefined になることがあります。

subprocess.stdio#

child_process.spawn() に渡される stdio オプション内の 'pipe' という値に設定された位置に対応する、子プロセスへのパイプの疎な配列です。subprocess.stdio[0]subprocess.stdio[1]、および subprocess.stdio[2] は、それぞれ subprocess.stdinsubprocess.stdout、および subprocess.stderr としても利用できます。

次の例では、子の fd 1 (stdout) のみがパイプとして設定されているため、親の subprocess.stdio[1] のみがストリームであり、配列内の他のすべての値は null です。

const assert = require('node:assert');
const fs = require('node:fs');
const child_process = require('node:child_process');

const subprocess = child_process.spawn('ls', {
  stdio: [
    0, // Use parent's stdin for child.
    'pipe', // Pipe child's stdout to parent.
    fs.openSync('err.out', 'w'), // Direct child's stderr to a file.
  ],
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);import assert from 'node:assert';
import fs from 'node:fs';
import child_process from 'node:child_process';

const subprocess = child_process.spawn('ls', {
  stdio: [
    0, // Use parent's stdin for child.
    'pipe', // Pipe child's stdout to parent.
    fs.openSync('err.out', 'w'), // Direct child's stderr to a file.
  ],
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);

子プロセスの生成に成功しなかった場合、subprocess.stdio プロパティは undefined になることがあります。

subprocess.stdout#

子プロセスの stdout を表す Readable Stream です。

子プロセスが stdio[1]'pipe' 以外に設定して生成された場合、これは null になります。

subprocess.stdoutsubprocess.stdio[1] のエイリアスです。両方のプロパティは同じ値を参照します。

const { spawn } = require('node:child_process');

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
  console.log(`Received chunk ${data}`);
});import { spawn } from 'node:child_process';

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
  console.log(`Received chunk ${data}`);
});

子プロセスの生成に成功しなかった場合、subprocess.stdout プロパティは null または undefined になることがあります。

subprocess.unref()#

デフォルトでは、親プロセスはデタッチされた子プロセスが終了するのを待ちます。親プロセスが特定の subprocess の終了を待たないようにするには、subprocess.unref() メソッドを使用します。これにより、親のイベントループは参照カウントに子プロセスを含めなくなり、子と親の間に確立されたIPCチャネルがない限り、親は子とは独立して終了できるようになります。

const { spawn } = require('node:child_process');
const process = require('node:process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();import { spawn } from 'node:child_process';
import process from 'node:process';

const subprocess = spawn(process.argv[0], ['child_program.js'], {
  detached: true,
  stdio: 'ignore',
});

subprocess.unref();

maxBuffer と Unicode#

maxBuffer オプションは stdout または stderr で許可される最大バイト数を指定します。この値を超えると、子プロセスは終了させられます。これは、UTF-8やUTF-16などのマルチバイト文字エンコーディングを含む出力に影響します。例えば、console.log('中文测试') は、4文字しかありませんが、13バイトのUTF-8エンコードされたバイトを stdout に送信します。

シェルの要件#

シェルは -c スイッチを理解する必要があります。シェルが 'cmd.exe' の場合、/d /s /c スイッチを理解し、コマンドラインのパースに互換性がある必要があります。

デフォルトの Windows シェル#

Microsoftは %COMSPEC% がルート環境で 'cmd.exe' へのパスを含まなければならないと規定していますが、子プロセスは必ずしも同じ要件に従うわけではありません。したがって、child_process の関数でシェルが生成されうる場合、process.env.ComSpec が利用できない場合のフォールバックとして 'cmd.exe' が使用されます。

高度なシリアライゼーション#

子プロセスは、HTMLの構造化複製アルゴリズムに基づいたnode:v8 モジュールのシリアライゼーションAPIに基づく、IPC用のシリアライゼーションメカニズムをサポートしています。これは一般的に、より強力で、BigIntMapSetArrayBufferTypedArrayBufferErrorRegExp など、より多くの組み込みJavaScriptオブジェクト型をサポートしています。

しかし、このフォーマットはJSONの完全なスーパーセットではなく、例えば、そのような組み込み型のオブジェクトに設定されたプロパティはシリアライズのステップを通じて渡されません。さらに、渡されるデータの構造によっては、パフォーマンスがJSONと同等ではない場合があります。したがって、この機能を使用するには、child_process.spawn() または child_process.fork() を呼び出す際に、serialization オプションを 'advanced' に設定してオプトインする必要があります。