@kreisler/exec-promise
A simple, promise-based wrapper for Node.js child_process.exec that makes executing shell commands easier and more modern.
Installation
npm install @kreisler/exec-promise
Overview
The native Node.js child_process.exec uses callbacks, which can be cumbersome in modern async/await code. This package wraps it in a Promise, making it easier to use with async/await syntax.
This package is designed for simple command execution. For more complex scenarios (streaming, real-time output), consider using child_process.spawn directly.
Basic Usage
import { execPromise } from '@kreisler/exec-promise' ;
const { stdout , stderr } = await execPromise ( 'echo "Hello World"' );
console . log ( stdout ); // "Hello World\n"
API Reference
execPromise
Executes a shell command and returns a promise that resolves with stdout and stderr.
async function execPromise (
comando : string
) : Promise <{ stdout : string ; stderr : string }>
The shell command to execute
Returns: Promise<{ stdout: string, stderr: string }>
The standard output from the command
The standard error output from the command
Throws: ExecException if the command fails
Examples
Simple Command Execution
import { execPromise } from '@kreisler/exec-promise' ;
async function runCommand () {
try {
const { stdout , stderr } = await execPromise ( 'ls -la' );
console . log ( 'Output:' , stdout );
if ( stderr ) {
console . error ( 'Errors:' , stderr );
}
} catch ( error ) {
console . error ( 'Command failed:' , error . message );
}
}
runCommand ();
const { execPromise } = require ( '@kreisler/exec-promise' );
async function runCommand () {
try {
const { stdout , stderr } = await execPromise ( 'ls -la' );
console . log ( 'Output:' , stdout );
if ( stderr ) {
console . error ( 'Errors:' , stderr );
}
} catch ( error ) {
console . error ( 'Command failed:' , error . message );
}
}
runCommand ();
Windows Commands
import { execPromise } from '@kreisler/exec-promise' ;
// Windows example
const { stdout } = await execPromise ( 'echo %PATH%' );
console . log ( 'System PATH:' , stdout );
// Directory listing on Windows
const { stdout : files } = await execPromise ( 'dir' );
console . log ( files );
Git Commands
import { execPromise } from '@kreisler/exec-promise' ;
async function getGitInfo () {
try {
// Get current branch
const { stdout : branch } = await execPromise ( 'git branch --show-current' );
console . log ( 'Current branch:' , branch . trim ());
// Get git status
const { stdout : status } = await execPromise ( 'git status --short' );
console . log ( 'Git status:' , status );
// Get last commit
const { stdout : lastCommit } = await execPromise (
'git log -1 --pretty=format:"%h - %an: %s"'
);
console . log ( 'Last commit:' , lastCommit );
} catch ( error ) {
console . error ( 'Git command failed:' , error . message );
}
}
getGitInfo ();
NPM/Package Manager Commands
import { execPromise } from '@kreisler/exec-promise' ;
async function installDependencies () {
console . log ( 'Installing dependencies...' );
try {
const { stdout , stderr } = await execPromise ( 'npm install' );
console . log ( stdout );
if ( stderr && ! stderr . includes ( 'npm WARN' )) {
console . error ( 'Installation errors:' , stderr );
}
console . log ( 'Installation complete!' );
} catch ( error ) {
console . error ( 'Installation failed:' , error . message );
}
}
installDependencies ();
Build Scripts
import { execPromise } from '@kreisler/exec-promise' ;
async function buildProject () {
const steps = [
{ name: 'Linting' , command: 'npm run lint' },
{ name: 'Testing' , command: 'npm test' },
{ name: 'Building' , command: 'npm run build' }
];
for ( const step of steps ) {
console . log ( ` \n ${ step . name } ...` );
try {
const { stdout , stderr } = await execPromise ( step . command );
console . log ( stdout );
if ( stderr ) {
console . warn ( 'Warnings:' , stderr );
}
} catch ( error ) {
console . error ( ` ${ step . name } failed:` , error . message );
process . exit ( 1 );
}
}
console . log ( ' \n Build completed successfully!' );
}
buildProject ();
Environment Variables
import { execPromise } from '@kreisler/exec-promise' ;
async function checkEnvironment () {
// Unix/Linux/macOS
const { stdout : nodeVersion } = await execPromise ( 'node --version' );
console . log ( 'Node version:' , nodeVersion . trim ());
const { stdout : npmVersion } = await execPromise ( 'npm --version' );
console . log ( 'NPM version:' , npmVersion . trim ());
// Check environment variable
const { stdout : home } = await execPromise ( 'echo $HOME' );
console . log ( 'Home directory:' , home . trim ());
}
checkEnvironment ();
Common Use Cases
import { execPromise } from '@kreisler/exec-promise' ;
// Create directory
await execPromise ( 'mkdir -p ./output/logs' );
// Copy files
await execPromise ( 'cp ./src/config.json ./dist/' );
// Remove files
await execPromise ( 'rm -rf ./temp' );
// Check if file exists
try {
await execPromise ( 'test -f ./config.json' );
console . log ( 'File exists' );
} catch {
console . log ( 'File does not exist' );
}
import { execPromise } from '@kreisler/exec-promise' ;
async function checkNetwork () {
// Ping a server
try {
const { stdout } = await execPromise ( 'ping -c 4 google.com' );
console . log ( 'Ping results:' , stdout );
} catch ( error ) {
console . error ( 'Network unreachable' );
}
// Get IP address
const { stdout : ip } = await execPromise (
'hostname -I | awk \' {print $1} \' '
);
console . log ( 'IP address:' , ip . trim ());
}
checkNetwork ();
import { execPromise } from '@kreisler/exec-promise' ;
async function manageDocker () {
// List containers
const { stdout : containers } = await execPromise ( 'docker ps' );
console . log ( 'Running containers:' , containers );
// Build image
await execPromise ( 'docker build -t myapp:latest .' );
// Run container
const { stdout : containerId } = await execPromise (
'docker run -d -p 3000:3000 myapp:latest'
);
console . log ( 'Container ID:' , containerId . trim ());
// Get logs
const { stdout : logs } = await execPromise (
`docker logs ${ containerId . trim () } `
);
console . log ( 'Container logs:' , logs );
}
manageDocker ();
Error Handling
Always wrap execPromise calls in try-catch blocks to handle command failures.
import { execPromise } from '@kreisler/exec-promise' ;
async function safeExec ( command : string ) {
try {
const { stdout , stderr } = await execPromise ( command );
return {
success: true ,
stdout ,
stderr ,
error: null
};
} catch ( error ) {
return {
success: false ,
stdout: '' ,
stderr: '' ,
error: error . message
};
}
}
// Usage
const result = await safeExec ( 'npm test' );
if ( result . success ) {
console . log ( 'Command succeeded:' , result . stdout );
} else {
console . error ( 'Command failed:' , result . error );
}
Best Practices
Validate Commands
Always validate and sanitize command inputs to prevent command injection: function isValidFilename ( name : string ) : boolean {
return / ^ [ a-zA-Z0-9._- ] + $ / . test ( name );
}
async function safeDelete ( filename : string ) {
if ( ! isValidFilename ( filename )) {
throw new Error ( 'Invalid filename' );
}
await execPromise ( `rm ${ filename } ` );
}
Handle Both stdout and stderr
Check both output streams as some programs write to stderr even on success: const { stdout , stderr } = await execPromise ( 'npm install' );
if ( stderr && ! stderr . includes ( 'npm WARN' )) {
console . error ( 'Actual errors:' , stderr );
}
Set Timeouts
For long-running commands, consider implementing timeouts: async function execWithTimeout ( command : string , timeoutMs : number ) {
const timeoutPromise = new Promise (( _ , reject ) => {
setTimeout (() => reject ( new Error ( 'Command timeout' )), timeoutMs );
});
return Promise . race ([
execPromise ( command ),
timeoutPromise
]);
}
Use Cross-Platform Commands
Be aware of platform differences when writing commands: const isWindows = process . platform === 'win32' ;
const command = isWindows
? 'dir'
: 'ls -la' ;
const { stdout } = await execPromise ( command );
Limitations
When to use execPromise:
Simple, short-lived commands
When you need the complete output after execution
Scripts and automation tasks
When NOT to use execPromise:
Long-running processes (use spawn instead)
When you need real-time output streaming
When you need to interact with the process (stdin)
Large output that may exceed buffer size
Type Exports
import type { Terror } from '@kreisler/exec-promise' ;
// Terror: ExecException | null
The Terror type is exported from Node.js child_process.ExecException.
Comparison with Native exec
Native exec
With @kreisler/exec-promise
import { exec } from 'child_process' ;
exec ( 'echo "Hello"' , ( error , stdout , stderr ) => {
if ( error ) {
console . error ( 'Error:' , error );
return ;
}
console . log ( 'Output:' , stdout );
});
License
MIT License - see the LICENSE file for details.
Links