spawn()spawn()の仕組みspawnSync()spawn()に基づく非同期ヘルパー関数exec()execFile()spawnAsync()に基づく同期ヘルパー関数execSync()execFileSync()'node:child_process'の関数の中から選択するこの章では、モジュール'node:child_process'を使用して、Node.jsからシェルコマンドを実行する方法について説明します。
モジュール'node:child_process'には、シェルコマンドを(*生成された*子プロセスで)実行するための関数が2つのバージョンで用意されています。
spawn()。spawnSync()。最初にspawn()、次にspawnSync()について説明します。最後に、これらに基づいており、比較的類似している以下の関数について説明します。
spawn()に基づくexec()execFile()spawnSync()に基づくexecSync()execFileSync()この章で示されているコードはUnix上で動作しますが、Windows上でもテスト済みです。Windowsでは、ほとんどのコードがわずかな変更(行末を'\n'ではなく'\r\n'にするなど)で動作します。
以下の機能は例でよく出てきます。そのため、ここで一度説明します。
アサーション: プリミティブ値にはassert.equal()、オブジェクトにはassert.deepEqual()を使用します。必要なインポートは例では表示されません。
import * as assert from 'node:assert/strict';関数Readable.toWeb()は、Nodeのネイティブstream.ReadableをWebストリーム(ReadableStreamのインスタンス)に変換します。§10 "Node.jsでのWebストリームの使用"で説明されています。Readableは例では常にインポートされます。
非同期関数readableStreamToString()は、読み取り可能なWebストリームを消費し、文字列(Promiseでラップされている)を返します。Webストリームに関する章で説明されています。この関数は例では使用可能であると想定されています。
spawn()spawn()の仕組みspawn(
command: string,
args?: Array<string>,
options?: Object
): ChildProcessspawn()は、新しいプロセスでコマンドを非同期に実行します。プロセスはNodeのメインJavaScriptプロセスと並行して実行され、さまざまな方法(多くの場合、ストリームを介して)で通信できます。
次に、spawn()のパラメータと結果のドキュメントがあります。例から学びたい場合は、このコンテンツをスキップして、次のサブセクションに進んでください。
commandcommandはシェルコマンドを含む文字列です。このパラメータを使用するには、2つのモードがあります。
argsは省略され、commandにはシェルコマンド全体が含まれます。複数の実行可能ファイル間のパイプ、ファイルへのI/Oのリダイレクト、変数、ワイルドカードなどのシェル機能も使用できます。options.shellはtrueでなければなりません。commandにはコマンドの名前のみが含まれ、argsにはその引数が含まれます。options.shellがtrueの場合、引数内の多くのメタ文字が解釈され、ワイルドカードや変数名などの機能が動作します。options.shellがfalseの場合、文字列は逐語的に使用され、メタ文字をエスケープする必要はありません。どちらのモードもこの章の後半で説明します。
options以下のoptionsが最も重要です。
.shell: boolean|string (デフォルト: false)trueにする必要があります。たとえば、.batファイルと.cmdファイルは、そうでなければ実行できません。.shellがfalseの場合、コアシェル機能(例: パイプ、I/Oリダイレクト、ファイル名ワイルドカード、変数)のみ使用できません。.shellがtrueの場合、任意のコードを実行しやすいため、ユーザー入力に注意してサニタイズする必要があります。また、メタ文字をメタ文字以外として使用したい場合は、エスケープする必要があります。.shellをシェル実行可能ファイルのパスに設定することもできます。すると、Node.jsはその実行可能ファイルを使用してコマンドを実行します。.shellをtrueに設定すると、Node.jsは以下を使用します。'/bin/sh'process.env.ComSpec.cwd: string | URL.stdio: Array<string|Stream>|string.env: Object (デフォルト: process.env)既存の変数を確認するには、process.envを(例: Node.js REPLで)参照してください。
スプレッド構文を使用して、既存の変数を非破壊的にオーバーライドしたり、まだ存在しない場合は作成したりできます。
{env: {...process.env, MY_VAR: 'Hi!'}}.signal: AbortSignalacを作成する場合、ac.signalをspawn()に渡して、ac.abort()を介して子プロセスを中止できます。これはこの章の後半で説明します。.timeout: number.timeoutミリ秒を超えると、強制終了されます。options.stdio子プロセスの標準I/Oストリームにはそれぞれ、数値ID、いわゆる*ファイル記述子*があります。
ファイル記述子は他にもありますが、まれです。
options.stdioは、子プロセスのストリームが親プロセスのストリームにパイプされるかどうか、およびどのようにパイプされるかを設定します。これは配列にすることができ、各要素はインデックスと同じファイル記述子を設定します。配列要素として以下の値を使用できます。
:'pipe'
childProcess.stdinを子のstdinにパイプします。名前とは異なり、前者は親プロセスに属するストリームであることに注意してください。childProcess.stdoutにパイプします。childProcess.stderrにパイプします。'ignore': 子のストリームを無視します。
'inherit': 子のストリームを親プロセスの対応するストリームにパイプします。
'inherit'を使用できます。ネイティブNode.jsストリーム: そのストリームとの間でパイプします。
他の値もサポートされていますが、この章の範囲外です。
配列を介してoptions.stdioを指定する代わりに、省略することもできます。
'pipe'は['pipe', 'pipe', 'pipe']と同等です(options.stdioのデフォルト)。'ignore'は['ignore', 'ignore', 'ignore']と同等です。'inherit'は['inherit', 'inherit', 'inherit']と同等です。ChildProcessのインスタンスspawn()はChildProcessのインスタンスを返します。
興味深いデータプロパティ
.exitCode: number | nullnullはプロセスがまだ終了していないことを意味します。.signalCode: string | nullnullです。詳細については、以下のメソッド.kill()の説明を参照してください。.stdin.stdout.stderr.pid: number | undefined.pidはundefinedです。この値は、spawn()を呼び出した直後に使用できます。興味深いメソッド
.kill(signalCode?: number | string = 'SIGTERM'): boolean
子プロセスにPOSIXシグナルを送信します(通常、これはプロセスの終了につながります)。
signalのmanページには、値のリストが含まれています。SIGINT、SIGTERM、SIGKILL)をエミュレートします。詳細については、Node.jsのドキュメントを参照してください。このメソッドについては、この章の後半で説明します。
興味深いイベント
.on('exit', (exitCode: number|null, signalCode: string|null) => {})'close'は、子プロセスの終了後にすべてのstdioストリームが閉じられたときに通知します。.on('error', (err: Error) => {})'exit'イベントが発生する場合と発生しない場合があります。後でイベントを待機可能なPromiseに変換する方法について説明します。
非同期spawn()を使用する場合、コマンドの子プロセスは非同期に開始されます。次のコードはそれを示しています。
import {spawn} from 'node:child_process';
spawn(
'echo', ['Command starts'],
{
stdio: 'inherit',
shell: true,
}
);
console.log('After spawn()');これが出力です。
After spawn()
Command starts
このセクションでは、同じコマンド呼び出しを2つの方法で指定します。
commandで指定します。commandで指定し、引数を2番目のパラメータargsで指定します。import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
const childProcess = spawn(
'echo "Hello, how are you?"',
{
shell: true, // (A)
stdio: ['ignore', 'pipe', 'inherit'], // (B)
}
);
const stdout = Readable.toWeb(
childProcess.stdout.setEncoding('utf-8'));
// Result on Unix
assert.equal(
await readableStreamToString(stdout),
'Hello, how are you?\n' // (C)
);
// Result on Windows: '"Hello, how are you?"\r\n'引数を持つ各コマンドのみのスポーンでは、たとえこれが単純なものであっても、.shellをtrueにする必要があります(行A)。
行Bでは、標準I/Oの処理方法をspawn()に指示します。
childProcess.stdout(親プロセスに属するストリーム)にパイプします。この場合、子プロセスの出力のみに関心があります。そのため、出力を処理したら完了です。他の場合は、子が終了するまで待機する必要がある場合があります。その方法は後で説明します。
コマンドのみモードでは、シェルのより特異な点がわかります。たとえば、Windowsコマンドシェルの出力には二重引用符が含まれています(最後の行)。
import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
const childProcess = spawn(
'echo', ['Hello, how are you?'],
{
shell: true,
stdio: ['ignore', 'pipe', 'inherit'],
}
);
const stdout = Readable.toWeb(
childProcess.stdout.setEncoding('utf-8'));
// Result on Unix
assert.equal(
await readableStreamToString(stdout),
'Hello, how are you?\n'
);
// Result on Windows: 'Hello, how are you?\r\n'argsのメタ文字argsにメタ文字がある場合にどうなるかを見てみましょう。
import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
async function echoUser({shell, args}) {
const childProcess = spawn(
`echo`, args,
{
stdio: ['ignore', 'pipe', 'inherit'],
shell,
}
);
const stdout = Readable.toWeb(
childProcess.stdout.setEncoding('utf-8'));
return readableStreamToString(stdout);
}
// Results on Unix
assert.equal(
await echoUser({shell: false, args: ['$USER']}), // (A)
'$USER\n'
);
assert.equal(
await echoUser({shell: true, args: ['$USER']}), // (B)
'rauschma\n'
);
assert.equal(
await echoUser({shell: true, args: [String.raw`\$USER`]}), // (C)
'$USER\n'
);$)などのメタ文字は効果がありません(行A)。$USERは変数として解釈されます(行B)。アスタリスク(*)などの他のメタ文字でも同様の効果が発生します。
これらは、Unixシェルのメタ文字の2つの例でした。Windowsシェルには独自のメタ文字と独自の If we don't use a shell, meta-characters such as the dollar sign ($) have no effect (line A).エスケープ方法があります。
より多くのシェル機能を使用してみましょう(コマンドのみモードが必要です)。
import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
import {EOL} from 'node:os';
const childProcess = spawn(
`(echo cherry && echo apple && echo banana) | sort`,
{
stdio: ['ignore', 'pipe', 'inherit'],
shell: true,
}
);
const stdout = Readable.toWeb(
childProcess.stdout.setEncoding('utf-8'));
assert.equal(
await readableStreamToString(stdout),
'apple\nbanana\ncherry\n'
);これまでは、子プロセスの標準出力のみを読み取っていました。しかし、標準入力にデータを送信することもできます。
import {Readable, Writable} from 'node:stream';
import {spawn} from 'node:child_process';
const childProcess = spawn(
`sort`, // (A)
{
stdio: ['pipe', 'pipe', 'inherit'],
}
);
const stdin = Writable.toWeb(childProcess.stdin); // (B)
const writer = stdin.getWriter(); // (C)
try {
await writer.write('Cherry\n');
await writer.write('Apple\n');
await writer.write('Banana\n');
} finally {
writer.close();
}
const stdout = Readable.toWeb(
childProcess.stdout.setEncoding('utf-8'));
assert.equal(
await readableStreamToString(stdout),
'Apple\nBanana\nCherry\n'
);シェルコマンドsort(行A)を使用して、テキスト行をソートします。
行Bでは、Writable.toWeb()を使用して、ネイティブNode.jsストリームをWebストリームに変換します(詳細については、§10「Node.jsでのWebストリームの使用」を参照してください)。
ライターを介してWritableStreamに書き込む方法(行C)についても、Webストリームに関する章で説明しています。
以前は、シェルに次のコマンドを実行させていました。
(echo cherry && echo apple && echo banana) | sort
次の例では、エコー(行A)からソート(行B)まで、手動でパイプを実行します。
import {Readable, Writable} from 'node:stream';
import {spawn} from 'node:child_process';
const echo = spawn( // (A)
`echo cherry && echo apple && echo banana`,
{
stdio: ['ignore', 'pipe', 'inherit'],
shell: true,
}
);
const sort = spawn( // (B)
`sort`,
{
stdio: ['pipe', 'pipe', 'inherit'],
shell: true,
}
);
//==== Transferring chunks from echo.stdout to sort.stdin ====
const echoOut = Readable.toWeb(
echo.stdout.setEncoding('utf-8'));
const sortIn = Writable.toWeb(sort.stdin);
const sortInWriter = sortIn.getWriter();
try {
for await (const chunk of echoOut) { // (C)
await sortInWriter.write(chunk);
}
} finally {
sortInWriter.close();
}
//==== Reading sort.stdout ====
const sortOut = Readable.toWeb(
sort.stdout.setEncoding('utf-8'));
assert.equal(
await readableStreamToString(sortOut),
'apple\nbanana\ncherry\n'
);echoOutなどのReadableStreamsは、非同期で反復可能です。そのため、for-await-ofループを使用して、それらの_チャンク_(ストリーミングデータのフラグメント)を読み取ることができます。詳細については、§10「Node.jsでのWebストリームの使用」を参照してください。
失敗した終了には、主に3種類あります。
次のコードは、子プロセスをスポーンできない場合にどうなるかを示しています。この場合、原因はシェルのパスが実行可能ファイルを指していないことです(行A)。
import {spawn} from 'node:child_process';
const childProcess = spawn(
'echo hello',
{
stdio: ['inherit', 'inherit', 'pipe'],
shell: '/bin/does-not-exist', // (A)
}
);
childProcess.on('error', (err) => { // (B)
assert.equal(
err.toString(),
'Error: spawn /bin/does-not-exist ENOENT'
);
});これは、イベントを使用して子プロセスを操作する最初の例です。行Bでは、'error'イベントのイベントリスナーを登録します。子プロセスは、現在のコードフラグメントが終了した後に開始されます。これは、競合状態を防ぐのに役立ちます。リスニングを開始すると、イベントがまだ発生していないことを確認できます。
シェルコードにエラーが含まれている場合、'error'イベントは発生せず(行B)、ゼロ以外の終了コードを持つ'exit'イベントが発生します(行A)。
import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
const childProcess = spawn(
'does-not-exist',
{
stdio: ['inherit', 'inherit', 'pipe'],
shell: true,
}
);
childProcess.on('exit',
async (exitCode, signalCode) => { // (A)
assert.equal(exitCode, 127);
assert.equal(signalCode, null);
const stderr = Readable.toWeb(
childProcess.stderr.setEncoding('utf-8'));
assert.equal(
await readableStreamToString(stderr),
'/bin/sh: does-not-exist: command not found\n'
);
}
);
childProcess.on('error', (err) => { // (B)
console.error('We never get here!');
});Unixでプロセスが強制終了された場合、終了コードはnull(行C)で、シグナルコードは文字列です(行D)。
import {Readable} from 'node:stream';
import {spawn} from 'node:child_process';
const childProcess = spawn(
'kill $$', // (A)
{
stdio: ['inherit', 'inherit', 'pipe'],
shell: true,
}
);
console.log(childProcess.pid); // (B)
childProcess.on('exit', async (exitCode, signalCode) => {
assert.equal(exitCode, null); // (C)
assert.equal(signalCode, 'SIGTERM'); // (D)
const stderr = Readable.toWeb(
childProcess.stderr.setEncoding('utf-8'));
assert.equal(
await readableStreamToString(stderr),
'' // (E)
);
});エラー出力がないことに注意してください(行E)。
子プロセスが自身を強制終了する代わりに(行A)、より長い時間一時停止し、行Bでログに記録したプロセスIDを介して手動で強制終了することもできます。
Windowsで子プロセスを強制終了するとどうなりますか?
exitCodeは1です。signalCodeはnullです。コマンドが終了するまで待機したい場合があります。これは、イベントとPromiseを介して実現できます。
import * as fs from 'node:fs';
import {spawn} from 'node:child_process';
const childProcess = spawn(
`(echo first && echo second) > tmp-file.txt`,
{
shell: true,
stdio: 'inherit',
}
);
childProcess.on('exit', (exitCode, signalCode) => { // (A)
assert.equal(exitCode, 0);
assert.equal(signalCode, null);
assert.equal(
fs.readFileSync('tmp-file.txt', {encoding: 'utf-8'}),
'first\nsecond\n'
);
});標準のNode.jsイベントパターンを使用し、'exit'イベントのリスナーを登録します(行A)。
import * as fs from 'node:fs';
import {spawn} from 'node:child_process';
const childProcess = spawn(
`(echo first && echo second) > tmp-file.txt`,
{
shell: true,
stdio: 'inherit',
}
);
const {exitCode, signalCode} = await onExit(childProcess); // (A)
assert.equal(exitCode, 0);
assert.equal(signalCode, null);
assert.equal(
fs.readFileSync('tmp-file.txt', {encoding: 'utf-8'}),
'first\nsecond\n'
);行Aで使用するヘルパー関数onExit()は、'exit'イベントが発生した場合に履行されるPromiseを返します。
export function onExit(eventEmitter) {
return new Promise((resolve, reject) => {
eventEmitter.once('exit', (exitCode, signalCode) => {
if (exitCode === 0) { // (B)
resolve({exitCode, signalCode});
} else {
reject(new Error(
`Non-zero exit: code ${exitCode}, signal ${signalCode}`));
}
});
eventEmitter.once('error', (err) => { // (C)
reject(err);
});
});
}eventEmitterが失敗した場合、返されたPromiseは拒否され、awaitは行Aで例外をスローします。onExit()は2種類の障害を処理します。
exitCodeがゼロではありません(行B)。これは次の場合に発生します。exitCodeはゼロより大きくなります。exitCodeはnullで、signalCodeはnull以外です。'error'イベントが発生します(行C)。これは、子プロセスをスポーンできない場合に発生します。この例では、AbortControllerを使用してシェルコマンドを終了します。
import {spawn} from 'node:child_process';
const abortController = new AbortController(); // (A)
const childProcess = spawn(
`echo Hello`,
{
stdio: 'inherit',
shell: true,
signal: abortController.signal, // (B)
}
);
childProcess.on('error', (err) => {
assert.equal(
err.toString(),
'AbortError: The operation was aborted'
);
});
abortController.abort(); // (C)AbortControllerを作成し(行A)、そのシグナルをspawn()に渡し(行B)、AbortControllerを介してシェルコマンドを終了します(行C)。
子プロセスは非同期に開始されます(現在のコードフラグメントが実行された後)。そのため、プロセスが開始される前に中止することができ、この場合、出力は表示されません。
.kill()を介して子プロセスを終了する次の例では、メソッド.kill()(最後の行)を介して子プロセスを終了します。
import {spawn} from 'node:child_process';
const childProcess = spawn(
`echo Hello`,
{
stdio: 'inherit',
shell: true,
}
);
childProcess.on('exit', (exitCode, signalCode) => {
assert.equal(exitCode, null);
assert.equal(signalCode, 'SIGTERM');
});
childProcess.kill(); // default argument value: 'SIGTERM'ここでも、子プロセスが開始される前に(非同期に!)強制終了するため、出力はありません。
spawnSync()spawnSync(
command: string,
args?: Array<string>,
options?: Object
): ObjectspawnSync()はspawn()の同期バージョンです。子プロセスが終了するまで待機し、同期的に(!)オブジェクトを返します。
パラメータは、ほとんどspawn()のパラメータと同じです。optionsには、いくつかの追加プロパティがあります。たとえば、
.input: string | TypedArray | DataView.encoding: string(デフォルト:'buffer')関数はオブジェクトを返します。その最も興味深いプロパティは次のとおりです。
.stdout: Buffer | string.stderr: Buffer | string.status: number | nullnullが含まれます。終了コードまたはシグナルコードのいずれかはnull以外です。.signal: string | nullnullが含まれます。終了コードまたはシグナルコードのいずれかはnull以外です。.error?: Error非同期spawn()では、子プロセスは同時に実行され、ストリームを介して標準I/Oを読み取ることができました。対照的に、同期spawnSync()はストリームの内容を収集し、同期的に返します(次のサブセクションを参照)。
同期spawnSync()を使用する場合、コマンドの子プロセスは同期的に開始されます。次のコードはそれを示しています。
import {spawnSync} from 'node:child_process';
spawnSync(
'echo', ['Command starts'],
{
stdio: 'inherit',
shell: true,
}
);
console.log('After spawnSync()');これが出力です。
Command starts
After spawnSync()
次のコードは、標準出力を読み取る方法を示しています。
import {spawnSync} from 'node:child_process';
const result = spawnSync(
`echo rock && echo paper && echo scissors`,
{
stdio: ['ignore', 'pipe', 'inherit'], // (A)
encoding: 'utf-8', // (B)
shell: true,
}
);
console.log(result);
assert.equal(
result.stdout, // (C)
'rock\npaper\nscissors\n'
);
assert.equal(result.stderr, null); // (D)行Aでは、options.stdioを使用して、標準出力のみに関心があることをspawnSync()に指示します。標準入力を無視し、標準エラーを親プロセスにパイプします。
結果として、標準出力の結果プロパティのみを取得し(行C)、標準エラーのプロパティはnullになります(行D)。
spawnSync()が子プロセスの標準I/Oの処理に内部的に使用するストリームにアクセスできないため、options.encoding(行B)を介して使用するエンコーディングを指示します。
オプションプロパティ.input(行A)を介して、子プロセスの標準入力ストリームにデータを送信できます。
import {spawnSync} from 'node:child_process';
const result = spawnSync(
`sort`,
{
stdio: ['pipe', 'pipe', 'inherit'],
encoding: 'utf-8',
input: 'Cherry\nApple\nBanana\n', // (A)
}
);
assert.equal(
result.stdout,
'Apple\nBanana\nCherry\n'
);失敗した終了には、主に3種類あります(終了コードがゼロでない場合)。
スポーンに失敗した場合、spawn() は 'error' イベントを発行します。対照的に、spawnSync() は result.error にエラーオブジェクトを設定します。
import {spawnSync} from 'node:child_process';
const result = spawnSync(
'echo hello',
{
stdio: ['ignore', 'inherit', 'pipe'],
encoding: 'utf-8',
shell: '/bin/does-not-exist',
}
);
assert.equal(
result.error.toString(),
'Error: spawnSync /bin/does-not-exist ENOENT'
);シェルでエラーが発生した場合、終了コード result.status は 0 より大きく、result.signal は null です。
import {spawnSync} from 'node:child_process';
const result = spawnSync(
'does-not-exist',
{
stdio: ['ignore', 'inherit', 'pipe'],
encoding: 'utf-8',
shell: true,
}
);
assert.equal(result.status, 127);
assert.equal(result.signal, null);
assert.equal(
result.stderr, '/bin/sh: does-not-exist: command not found\n'
);子プロセスが Unix 上で強制終了された場合、result.signal にはシグナルの名前が含まれ、result.status は null です。
import {spawnSync} from 'node:child_process';
const result = spawnSync(
'kill $$',
{
stdio: ['ignore', 'inherit', 'pipe'],
encoding: 'utf-8',
shell: true,
}
);
assert.equal(result.status, null);
assert.equal(result.signal, 'SIGTERM');
assert.equal(result.stderr, ''); // (A)標準エラーストリームには何も出力されていないことに注意してください(行 A)。
Windows で子プロセスを強制終了した場合
result.status は 1 です。result.signal は null です。result.stderr は '' です。spawn() に基づく非同期ヘルパー関数このセクションでは、node:child_process モジュールの spawn() に基づく 2 つの非同期関数について説明します。
exec()execFile()この章では、fork() については無視します。Node.js のドキュメントを引用すると、
fork()は新しい Node.js プロセスをスポーンし、指定されたモジュールを呼び出します。この際、親プロセスと子プロセスの間でメッセージを送信できる IPC 通信チャネルが確立されます。
exec()exec(
command: string,
options?: Object,
callback?: (error, stdout, stderr) => void
): ChildProcessexec() は、新しくスポーンされたシェルでコマンドを実行します。spawn() との主な違いは次のとおりです。
exec() はコールバックを介して結果も配信します。エラーオブジェクト、または stdout と stderr の内容のいずれかです。spawn() は子プロセスをスポーンできない場合にのみ 'error' イベントを発行します。他の 2 つのエラーは、終了コードと(Unix では)シグナルコードによって処理されます。args はありません。options.shell のデフォルトは true です。import {exec} from 'node:child_process';
const childProcess = exec(
'echo Hello',
(error, stdout, stderr) => {
if (error) {
console.error('error: ' + error.toString());
return;
}
console.log('stdout: ' + stdout); // 'stdout: Hello\n'
console.error('stderr: ' + stderr); // 'stderr: '
}
);exec() は、util.promisify() を介して Promise ベースの関数に変換できます。
{stdout, stderr}error パラメータと同じ値ですが、2 つの追加プロパティ .stdout と .stderr があります。import * as util from 'node:util';
import * as child_process from 'node:child_process';
const execAsync = util.promisify(child_process.exec);
try {
const resultPromise = execAsync('echo Hello');
const {childProcess} = resultPromise;
const obj = await resultPromise;
console.log(obj); // { stdout: 'Hello\n', stderr: '' }
} catch (err) {
console.error(err);
}execFile()execFile(file, args?, options?, callback?): ChildProcess
exec() と同様に機能しますが、次の点が異なります。
args がサポートされています。options.shell のデフォルトは false です。exec() と同様に、execFile() は util.promisify() を介して Promise ベースの関数に変換できます。
spawnAsync() に基づく同期ヘルパー関数execSync()execSync(
command: string,
options?: Object
): Buffer | stringexecSync() は、新しい子プロセスでコマンドを実行し、そのプロセスが終了するまで同期的に待機します。spawnSync() との主な違いは次のとおりです。
spawnSync() の結果は、子プロセスをスポーンできない場合にのみ .error プロパティを持ちます。他の 2 つのエラーは、終了コードと(Unix では)シグナルコードによって処理されます。args はありません。options.shell のデフォルトは true です。import {execSync} from 'node:child_process';
try {
const stdout = execSync('echo Hello');
console.log('stdout: ' + stdout); // 'stdout: Hello\n'
} catch (err) {
console.error('Error: ' + err.toString());
}execFileSync()execFileSync(file, args?, options?): Buffer | string
execSync() と同様に機能しますが、次の点が異なります。
args がサポートされています。options.shell のデフォルトは false です。12.6.1 tinysh:シェルコマンドのスポーンを支援するヘルパー
import sh from 'tinysh';
console.log(sh.ls('-l'));
console.log(sh.cat('README.md'));Anton Medvedev によるtinysh は、シェルコマンドのスポーンを支援する小さなライブラリです。例:
sh.tee.call({input: 'Hello, world!'}, 'file.txt');.call() を使用してオブジェクトを this として渡すことで、デフォルトのオプションをオーバーライドできます。
import {execFileSync} from 'node:child_process';
const sh = new Proxy({}, {
get: (_, bin) => function (...args) { // (A)
return execFileSync(bin, args,
{
encoding: 'utf-8',
shell: true,
...this // (B)
}
);
},
});任意のプロパティ名を使用でき、tinysh はその名前でシェルコマンドを実行します。Proxy を介してこの機能を実現しています。これは、実際のライブラリを少し変更したバージョンです。
行 A では、sh から bin という名前のプロパティを取得すると、execFileSync() を呼び出し、bin を最初の引数として使用する関数が返されることがわかります。
this をスプレッドすることで、.call() を介してオプションを指定できます。デフォルトが最初に来るため、this を介してオーバーライドできます。12.6.2 node-powershell:Node.js を介して Windows PowerShell コマンドを実行する
import { PowerShell } from 'node-powershell';
PowerShell.$`echo "hello from PowerShell"`;12.7 'node:child_process' モジュールの関数の選択
spawn() は、エラーと標準 I/O コンテンツを配信するコールバックがないため、この場合よりシンプルです。exec() と execFile()同期オプション:spawnSync()、execSync()、execFileSync()
spawn() と exec() または execFile() の選択exec() と execFile() には 2 つの利点があります。これらの利点が重要でない場合は、spawn() を選択できます。(オプションの)コールバックがないため、シグネチャがよりシンプルです。
spawnSync() と execSync() または execFileSync() の選択execSync() と execFileSync() には 2 つの特性があります。execSync() と execFileSync() が戻り値と例外によって提供するよりも多くの情報が必要な場合は、spawnSync() を選択してください。
exec() と execFile() の選択(execSync() と execFileSync() の選択にも同じ引数が適用されます)options.shell のデフォルトは、exec() では true ですが、execFile() では false です。