Execute shell commands in Node.js with timeouts, abort control, and streaming output.
npm install @neabyte/exec-command
// CommonJS
const exec = require('@neabyte/exec-command')
// ESM (ES Modules)
import exec from '@neabyte/exec-command'
import exec from '@neabyte/exec-command'
// Simple command execution - collects all output before resolving
const result = await exec('echo "Hello World"')
console.log(result.stdout) // "Hello World"
console.log(result.stderr) // ""
console.log(result.exitCode) // 0
console.log(result.kill) // Function to terminate the process
// Real-time output streaming - processes data as it arrives
const stream = exec('ping -c 5 google.com', { stream: true })
// Process output in real-time using async iteration
for await (const chunk of stream.output) {
console.log(chunk.toString()) // Buffer containing raw output
}
// Wait for process completion
await stream.promise // Returns ExecResult when done
// Access kill method for early termination
stream.kill() // Terminates the process immediately
// Kill running processes - works for both streaming and buffered modes
const stream = exec('ping -c 20 google.com', { stream: true })
setTimeout(() => {
stream.kill() // Kill with default SIGTERM signal
stream.kill('SIGKILL') // Kill with specific signal
}, 5000)
// Buffered process can also be killed
const buffered = exec('long-running-command')
buffered.kill() // Terminates immediately, promise will reject
// Set timeout (in milliseconds) - process will be killed if it runs too long
const result = await exec('slow-command', { timeout: 5000 })
// Process will be killed after 5 seconds with SIGTERM, then SIGKILL after 5 more seconds
// No timeout (default)
const result2 = await exec('command', { timeout: 0 })
// Process runs indefinitely until completion or manual kill
// Execute in specific directory - changes the current working directory
const result = await exec('ls', { cwd: '/path/to/directory' })
// Lists files in the specified directory
// Use relative paths
const result2 = await exec('pwd', { cwd: './src' })
// Shows the absolute path of the src directory
// Custom environment variables - merged with existing process.env
const result = await exec('echo $MY_VAR', {
env: { MY_VAR: 'Hello World' }
})
// Output: "Hello World"
// Multiple environment variables
const result2 = await exec('node -e "console.log(process.env.VAR1, process.env.VAR2)"', {
env: {
VAR1: 'First',
VAR2: 'Second'
}
})
// Output: "First Second"
// Override existing environment variables
const result3 = await exec('echo $HOME', {
env: { HOME: '/custom/home' }
})
// Output: "/custom/home"
// Complex shell commands with operators - automatically detected and executed with shell
const result = await exec('ls -la | grep .txt')
// Lists files and filters for .txt files
// Chained commands with &&
const result2 = await exec('cd /tmp && pwd')
// Changes to /tmp directory and shows current path
// Environment variable expansion
const result3 = await exec('echo $HOME && echo $USER')
// Shows home directory and username
// Pipes and redirections
const result4 = await exec('echo "Hello" | wc -c')
// Counts characters in "Hello" (output: 6)
// Complex shell operations
const result5 = await exec('find . -name "*.js" | head -5')
// Finds first 5 JavaScript files
All options are optional and can be combined:
interface ExecOptions {
/** Timeout duration in milliseconds (0 = no timeout) */
timeout?: number
/** Enable streaming mode for real-time output */
stream?: boolean
/** Working directory for command execution */
cwd?: string
/** Environment variables to pass to the process */
env?: Record<string, string | undefined>
}
timeout
: Kill process after X milliseconds (0 = no timeout)stream
:true
= real-time output,false
= collect all output firstcwd
: Run command in this directoryenv
: Add these environment variables
Buffered Mode (stream: false
):
interface ExecResult {
stdout: string // Standard output
stderr: string // Standard error
exitCode: number // Process exit code
kill(signal?: string | number): void // Kill function
then: Promise<ExecResult>['then'] // Promise methods
catch: Promise<ExecResult>['catch']
finally: Promise<ExecResult>['finally']
}
Streaming Mode (stream: true
):
interface ExecStream {
output: AsyncIterable<Buffer> // Real-time output stream
promise: Promise<ExecResult> // Completion promise
kill(signal?: string | number): void // Kill function
}
This project is licensed under the MIT license. See the LICENSE file for more info.