execa-cjs
v9.1.1
Published
Process execution for humans
Downloads
70
Maintainers
Readme
Process execution for humans
Execa runs commands in your script, application or library. Unlike shells, it is optimized for programmatic usage. Built on top of the child_process
core module.
One of the maintainers @ehmicky is looking for a remote full-time position. Specialized in Node.js back-ends and CLIs, he led Netlify Build, Plugins and Configuration for 2.5 years. Feel free to contact him on his website or on LinkedIn!
Features
- Simple syntax: promises and template strings, like
zx
. - Script interface.
- No escaping nor quoting needed. No risk of shell injection.
- Execute locally installed binaries without
npx
. - Improved Windows support: shebangs,
PATHEXT
, and more. - Detailed errors and verbose mode, for debugging.
- Pipe multiple subprocesses better than in shells: retrieve intermediate results, use multiple sources/destinations, unpipe.
- Split the output into text lines, or iterate progressively over them.
- Strip unnecessary newlines.
- Pass any input to the subprocess: files, strings,
Uint8Array
s, iterables, objects and almost any other type. - Return almost any type from the subprocess, or redirect it to files.
- Get interleaved output from
stdout
andstderr
similar to what is printed on the terminal. - Retrieve the output programmatically and print it on the console at the same time.
- Transform or filter the input and output with simple functions.
- Pass Node.js streams or web streams to subprocesses, or convert subprocesses to a stream.
- Exchange messages with the subprocess.
- Ensure subprocesses exit even when they intercept termination signals, or when the current process ends abruptly.
Install
npm install execa
Documentation
Execution:
- ▶️ Basic execution
- 💬 Escaping/quoting
- 💻 Shell
- 📜 Scripts
- 🐢 Node.js files
- 🌐 Environment
- ❌ Errors
- 🏁 Termination
Input/output:
Advanced usage:
- 🔀 Piping multiple subprocesses
- ⏳️ Streams
- 📞 Inter-process communication
- 🐛 Debugging
- 📎 Windows
- 🔍 Difference with Bash and zx
- 🤓 TypeScript
- 📔 API reference
Examples
Execution
Simple syntax
import {execa} from 'execa';
const {stdout} = await execa`npm run build`;
// Print command's output
console.log(stdout);
Script
import {$} from 'execa';
const {stdout: name} = await $`cat package.json`.pipe`grep name`;
console.log(name);
const branch = await $`git branch --show-current`;
await $`dep deploy --branch=${branch}`;
await Promise.all([
$`sleep 1`,
$`sleep 2`,
$`sleep 3`,
]);
const directoryName = 'foo bar';
await $`mkdir /tmp/${directoryName}`;
Local binaries
$ npm install -D eslint
await execa({preferLocal: true})`eslint`;
Pipe multiple subprocesses
const {stdout, pipedFrom} = await execa`npm run build`
.pipe`sort`
.pipe`head -n 2`;
// Output of `npm run build | sort | head -n 2`
console.log(stdout);
// Output of `npm run build | sort`
console.log(pipedFrom[0].stdout);
// Output of `npm run build`
console.log(pipedFrom[0].pipedFrom[0].stdout);
Input/output
Interleaved output
const {all} = await execa({all: true})`npm run build`;
// stdout + stderr, interleaved
console.log(all);
Programmatic + terminal output
const {stdout} = await execa({stdout: ['pipe', 'inherit']})`npm run build`;
// stdout is also printed to the terminal
console.log(stdout);
Simple input
const {stdout} = await execa({input: getInputString()})`sort`;
console.log(stdout);
File input
// Similar to: npm run build < input.txt
await execa({stdin: {file: 'input.txt'}})`npm run build`;
File output
// Similar to: npm run build > output.txt
await execa({stdout: {file: 'output.txt'}})`npm run build`;
Split into text lines
const {stdout} = await execa({lines: true})`npm run build`;
// Print first 10 lines
console.log(stdout.slice(0, 10).join('\n'));
Streaming
Iterate over text lines
for await (const line of execa`npm run build`) {
if (line.includes('WARN')) {
console.warn(line);
}
}
Transform/filter output
let count = 0;
// Filter out secret lines, then prepend the line number
const transform = function * (line) {
if (!line.includes('secret')) {
yield `[${count++}] ${line}`;
}
};
await execa({stdout: transform})`npm run build`;
Web streams
const response = await fetch('https://example.com');
await execa({stdin: response.body})`sort`;
Convert to Duplex stream
import {execa} from 'execa';
import {pipeline} from 'node:stream/promises';
import {createReadStream, createWriteStream} from 'node:fs';
await pipeline(
createReadStream('./input.txt'),
execa`node ./transform.js`.duplex(),
createWriteStream('./output.txt'),
);
IPC
Exchange messages
// parent.js
import {execaNode} from 'execa';
const subprocess = execaNode`child.js`;
console.log(await subprocess.getOneMessage()); // 'Hello from child'
await subprocess.sendMessage('Hello from parent');
const result = await subprocess;
// child.js
import {sendMessage, getOneMessage} from 'execa';
await sendMessage('Hello from child');
console.log(await getOneMessage()); // 'Hello from parent'
Any input type
// main.js
import {execaNode} from 'execa';
const ipcInput = [
{task: 'lint', ignore: /test\.js/},
{task: 'copy', files: new Set(['main.js', 'index.js']),
}];
await execaNode({ipcInput})`build.js`;
// build.js
import {getOneMessage} from 'execa';
const ipcInput = await getOneMessage();
Any output type
// main.js
import {execaNode} from 'execa';
const {ipcOutput} = await execaNode`build.js`;
console.log(ipcOutput[0]); // {kind: 'start', timestamp: date}
console.log(ipcOutput[1]); // {kind: 'stop', timestamp: date}
// build.js
import {sendMessage} from 'execa';
await sendMessage({kind: 'start', timestamp: new Date()});
await runBuild();
await sendMessage({kind: 'stop', timestamp: new Date()});
Debugging
Detailed error
import {execa, ExecaError} from 'execa';
try {
await execa`unknown command`;
} catch (error) {
if (error instanceof ExecaError) {
console.log(error);
}
/*
ExecaError: Command failed with ENOENT: unknown command
spawn unknown ENOENT
at ...
at ... {
shortMessage: 'Command failed with ENOENT: unknown command\nspawn unknown ENOENT',
originalMessage: 'spawn unknown ENOENT',
command: 'unknown command',
escapedCommand: 'unknown command',
cwd: '/path/to/cwd',
durationMs: 28.217566,
failed: true,
timedOut: false,
isCanceled: false,
isTerminated: false,
isMaxBuffer: false,
code: 'ENOENT',
stdout: '',
stderr: '',
stdio: [undefined, '', ''],
pipedFrom: []
[cause]: Error: spawn unknown ENOENT
at ...
at ... {
errno: -2,
code: 'ENOENT',
syscall: 'spawn unknown',
path: 'unknown',
spawnargs: [ 'command' ]
}
}
*/
}
Verbose mode
await execa`npm run build`;
await execa`npm run test`;
Related
- gulp-execa - Gulp plugin for Execa
- nvexeca - Run Execa using any Node.js version