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.