- Notifications
You must be signed in to change notification settings - Fork233
Process execution for humans
License
NotificationsYou must be signed in to change notification settings
sindresorhus/execa
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Process execution for humans
Execa runs commands in your script, application or library. Unlike shells, it isoptimized for programmatic usage. Built on top of thechild_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 NetlifyBuild,Plugins and Configuration for 2.5 years. Feel free to contact him onhis website or onLinkedIn!
- Simple syntax: promises andtemplate strings, like
zx
. - Script interface.
- No escaping nor quoting needed. No risk of shell injection.
- Executelocally installed binaries without
npx
. - ImprovedWindows support:shebangs,
PATHEXT
,graceful termination,and more. - Detailed errors,verbose mode andcustom logging, fordebugging.
- Pipe multiple subprocesses better than in shells: retrieveintermediate results, use multiplesources/destinations,unpipe.
- Split the output into text lines, oriterate progressively over them.
- Stripunnecessary newlines.
- Pass anyinput to the subprocess:files,strings,
Uint8Array
s,iterables,objects and almost anyother type. - Returnalmost any type from the subprocess, or redirect it tofiles.
- Getinterleaved output from
stdout
andstderr
similar to what is printed on the terminal. - Retrieve the outputprogrammatically and print it on the console at the same time.
- Transform or filter the input and output withsimple functions.
- PassNode.js streams orweb streams to subprocesses, orconvert subprocesses toa stream.
- Exchange messages with the subprocess.
- Ensure subprocesses exit even when theyintercept termination signals, or when the current processends abruptly.
npm install execa
Execution:
Input/output:
Advanced usage:
- 🔀Piping multiple subprocesses
- ⏳️Streams
- 📞Inter-process communication
- 🐛Debugging
- 📎Windows
- 🔍Difference with Bash and zx
- 🐭Small packages
- 🤓TypeScript
- 📔API reference
import{execa}from'execa';const{stdout}=awaitexeca`npm run build`;// Print command's outputconsole.log(stdout);
import{$}from'execa';const{stdout:name}=await$`cat package.json`.pipe`grep name`;console.log(name);constbranch=await$`git branch --show-current`;await$`dep deploy --branch=${branch}`;awaitPromise.all([$`sleep 1`,$`sleep 2`,$`sleep 3`,]);constdirectoryName='foo bar';await$`mkdir /tmp/${directoryName}`;
$ npm install -D eslint
awaitexeca({preferLocal:true})`eslint`;
const{stdout, pipedFrom}=awaitexeca`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);
const{all}=awaitexeca({all:true})`npm run build`;// stdout + stderr, interleavedconsole.log(all);
const{stdout}=awaitexeca({stdout:['pipe','inherit']})`npm run build`;// stdout is also printed to the terminalconsole.log(stdout);
constgetInputString=()=>{/* ... */};const{stdout}=awaitexeca({input:getInputString()})`sort`;console.log(stdout);
// Similar to: npm run build < input.txtawaitexeca({stdin:{file:'input.txt'}})`npm run build`;
// Similar to: npm run build > output.txtawaitexeca({stdout:{file:'output.txt'}})`npm run build`;
const{stdout}=awaitexeca({lines:true})`npm run build`;// Print first 10 linesconsole.log(stdout.slice(0,10).join('\n'));
forawait(constlineofexeca`npm run build`){if(line.includes('WARN')){console.warn(line);}}
letcount=0;// Filter out secret lines, then prepend the line numberconsttransform=function*(line){if(!line.includes('secret')){yield`[${count++}]${line}`;}};awaitexeca({stdout:transform})`npm run build`;
constresponse=awaitfetch('https://example.com');awaitexeca({stdin:response.body})`sort`;
import{execa}from'execa';import{pipeline}from'node:stream/promises';import{createReadStream,createWriteStream}from'node:fs';awaitpipeline(createReadStream('./input.txt'),execa`node ./transform.js`.duplex(),createWriteStream('./output.txt'),);
// parent.jsimport{execaNode}from'execa';constsubprocess=execaNode`child.js`;awaitsubprocess.sendMessage('Hello from parent');constmessage=awaitsubprocess.getOneMessage();console.log(message);// 'Hello from child'
// child.jsimport{getOneMessage,sendMessage}from'execa';constmessage=awaitgetOneMessage();// 'Hello from parent'constnewMessage=message.replace('parent','child');// 'Hello from child'awaitsendMessage(newMessage);
// main.jsimport{execaNode}from'execa';constipcInput=[{task:'lint',ignore:/test\.js/},{task:'copy',files:newSet(['main.js','index.js']),}];awaitexecaNode({ipcInput})`build.js`;
// build.jsimport{getOneMessage}from'execa';constipcInput=awaitgetOneMessage();
// main.jsimport{execaNode}from'execa';const{ipcOutput}=awaitexecaNode`build.js`;console.log(ipcOutput[0]);// {kind: 'start', timestamp: date}console.log(ipcOutput[1]);// {kind: 'stop', timestamp: date}
// build.jsimport{sendMessage}from'execa';construnBuild=()=>{/* ... */};awaitsendMessage({kind:'start',timestamp:newDate()});awaitrunBuild();awaitsendMessage({kind:'stop',timestamp:newDate()});
// main.jsimport{execaNode}from'execa';constcontroller=newAbortController();setTimeout(()=>{controller.abort();},5000);awaitexecaNode({cancelSignal:controller.signal,gracefulCancel:true,})`build.js`;
// build.jsimport{getCancelSignal}from'execa';constcancelSignal=awaitgetCancelSignal();consturl='https://example.com/build/info';constresponse=awaitfetch(url,{signal:cancelSignal});
import{execa,ExecaError}from'execa';try{awaitexeca`unknown command`;}catch(error){if(errorinstanceofExecaError){console.log(error);}/*ExecaError: Command failed with ENOENT: unknown commandspawn unknown ENOENTat ...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 ENOENTat ...at ... {errno: -2,code: 'ENOENT',syscall: 'spawn unknown',path: 'unknown',spawnargs: [ 'command' ]}}*/}
awaitexeca`npm run build`;awaitexeca`npm run test`;
import{execaasexeca_}from'execa';import{createLogger,transports}from'winston';// Log to a file using Winstonconsttransport=newtransports.File({filename:'logs.txt'});constlogger=createLogger({transports:[transport]});constLOG_LEVELS={command:'info',output:'verbose',ipc:'verbose',error:'error',duration:'info',};constexeca=execa_({verbose(verboseLine,{message, ...verboseObject}){constlevel=LOG_LEVELS[verboseObject.type];logger[level](message,verboseObject);},});awaitexeca`npm run build`;awaitexeca`npm run test`;
- nano-spawn - Like Execa butsmaller
- gulp-execa - Gulp plugin for Execa
- nvexeca - Run Execa using any Node.js version
About
Process execution for humans
Topics
Resources
License
Code of conduct
Security policy
Stars
Watchers
Forks
Packages0
No packages published