execa logo
# 🔀 Piping multiple subprocesses ## Array syntax A subprocess' [output](output.md) can be [piped](https://en.wikipedia.org/wiki/Pipeline_(Unix)) to another subprocess' [input](input.md). The syntax is the same as [`execa(file, arguments?, options?)`](execution.md#array-syntax). ```js import {execa} from 'execa'; // Similar to `npm run build | head -n 2` in shells const {stdout} = await execa('npm', ['run', 'build']) .pipe('head', ['-n', '2']); ``` ## Template string syntax ```js const {stdout} = await execa`npm run build` .pipe`head -n 2`; ``` ## Advanced syntax ```js const subprocess = execa`head -n 2`; const {stdout} = await execa`npm run build` .pipe(subprocess); ``` ## Options [Options](api.md#options-1) can be passed to either the source or the destination subprocess. Some [pipe-specific options](api.md#pipeoptions) can also be set by the destination subprocess. ```js const {stdout} = await execa('npm', ['run', 'build'], subprocessOptions) .pipe('head', ['-n', '2'], subprocessOrPipeOptions); ``` ```js const {stdout} = await execa(subprocessOptions)`npm run build` .pipe(subprocessOrPipeOptions)`head -n 2`; ``` ```js const subprocess = execa(subprocessOptions)`head -n 2`; const {stdout} = await execa(subprocessOptions)`npm run build` .pipe(subprocess, pipeOptions); ``` ## Result When both subprocesses succeed, the [`result`](api.md#result) of the destination subprocess is returned. The [`result`](api.md#result) of the source subprocess is available in a [`result.pipedFrom`](api.md#resultpipedfrom) array. ```js const destinationResult = await execa`npm run build` .pipe`head -n 2`; console.log(destinationResult.stdout); // First 2 lines of `npm run build` const sourceResult = destinationResult.pipedFrom[0]; console.log(sourceResult.stdout); // Full output of `npm run build` ``` ## Errors When either subprocess fails, `subprocess.pipe()` is rejected with that subprocess' error. If the destination subprocess fails, [`error.pipedFrom`](api.md#resultpipedfrom) includes the source subprocess' result, which is useful for debugging. ```js try { await execa`npm run build` .pipe`head -n 2`; } catch (error) { if (error.pipedFrom.length === 0) { // `npm run build` failure console.error(error); } else { // `head -n 2` failure console.error(error); // `npm run build` output console.error(error.pipedFrom[0].stdout); } throw error; } ``` ## Series of subprocesses ```js await execa`npm run build` .pipe`sort` .pipe`head -n 2`; ``` ## 1 source, multiple destinations ```js const subprocess = execa`npm run build`; const [sortedResult, truncatedResult] = await Promise.all([ subprocess.pipe`sort`, subprocess.pipe`head -n 2`, ]); ``` ## Multiple sources, 1 destination ```js const destination = execa`./log-remotely.js`; await Promise.all([ execa`npm run build`.pipe(destination), execa`npm run test`.pipe(destination), ]); ``` ## Source file descriptor By default, the source's [`stdout`](api.md#subprocessstdout) is used, but this can be changed using the [`from`](api.md#pipeoptionsfrom) piping option. ```js await execa`npm run build` .pipe({from: 'stderr'})`head -n 2`; ``` ## Destination file descriptor By default, the destination's [`stdin`](api.md#subprocessstdin) is used, but this can be changed using the [`to`](api.md#pipeoptionsto) piping option. ```js await execa`npm run build` .pipe({to: 'fd3'})`./log-remotely.js`; ``` ## Unpipe Piping can be stopped using the [`unpipeSignal`](api.md#pipeoptionsunpipesignal) piping option. The [`subprocess.pipe()`](api.md#subprocesspipefile-arguments-options) method will be rejected with a cancelation error. However, each subprocess will keep running. ```js const abortController = new AbortController(); process.on('SIGUSR1', () => { abortController.abort(); }); // If the process receives SIGUSR1, `npm run build` stopped being logged remotely. // However, it keeps running successfully. try { await execa`npm run build` .pipe({unpipeSignal: abortController.signal})`./log-remotely.js`; } catch (error) { if (!abortController.signal.aborted) { throw error; } } ```
[**Next**: ⏳️ Streams](streams.md)\ [**Previous**: 🧙 Transforms](transform.md)\ [**Top**: Table of contents](../readme.md#documentation)