Portable Unix shell commands for Node.js that provide cross-platform compatibility across Windows, Linux, and macOS.
—
Commands for executing external processes, managing directory stacks, and controlling the shell environment and program flow.
Executes external shell commands synchronously or asynchronously with comprehensive options for process control.
/**
* Execute external shell commands
* @param command - Command string to execute
* @param options - Execution options
* @param callback - Optional callback for async execution
* @returns ShellString with code, stdout, and stderr properties
*/
function exec(command: string, options?: ExecOptions, callback?: ExecCallback): ShellString;
function exec(command: string, callback: ExecCallback): ShellString;
interface ExecOptions {
/** Character encoding for output (default: 'utf8') */
encoding?: string;
/** Suppress command output (default: false) */
silent?: boolean;
/** Execute asynchronously when callback provided (default: false) */
async?: boolean;
/** Throw error on non-zero exit code (default: config.fatal) */
fatal?: boolean;
/** Working directory for command execution */
cwd?: string;
/** Environment variables for the process */
env?: NodeJS.ProcessEnv;
/** Maximum buffer size for stdout/stderr (default: 20MB) */
maxBuffer?: number;
}
type ExecCallback = (code: number, stdout: string, stderr: string) => void;Usage Examples:
// Simple synchronous execution
const result = shell.exec('ls -la');
console.log('Exit code:', result.code);
console.log('Output:', result.stdout);
// Check exit code for errors
if (shell.exec('npm test').code !== 0) {
shell.echo('Tests failed');
shell.exit(1);
}
// Asynchronous execution with callback
shell.exec('long-running-command', function(code, stdout, stderr) {
console.log('Exit code:', code);
console.log('Output:', stdout);
});
// Execution with options
const gitResult = shell.exec('git status', {
silent: true,
cwd: '/path/to/repo',
env: { ...process.env, GIT_AUTHOR_NAME: 'Bot' }
});
// Capture output
const version = shell.exec('node --version', { silent: true }).stdout.trim();
// Error handling with fatal mode
shell.exec('risky-command', { fatal: true }); // Throws on non-zero exit
// Custom environment
shell.exec('echo $CUSTOM_VAR', {
env: { ...process.env, CUSTOM_VAR: 'custom_value' }
});
// Working directory
shell.exec('pwd', { cwd: '/tmp' });Exits the current Node.js process with an optional exit code.
/**
* Exit current process with optional exit code
* @param code - Exit code (default: 0 for success)
*/
function exit(code?: number): void;Usage Examples:
// Exit with success
shell.exit();
shell.exit(0);
// Exit with error code
shell.exit(1);
// Conditional exit
if (!shell.which('git')) {
shell.echo('Git is required');
shell.exit(1);
}
// Exit after error
if (shell.exec('npm test').code !== 0) {
shell.exit(1);
}Pushes the current directory onto the directory stack and optionally changes to a new directory.
/**
* Push directory onto stack and optionally change to new directory
* @param options - Command options
* @param dir - Directory to change to, or stack position ('+N', '-N')
* @returns ShellString containing directory stack as array
*/
function pushd(options?: string, dir?: string): ShellString;
function pushd(dir?: string): ShellString;Options:
-n: Don't change directory, just manipulate stackUsage Examples:
// Push current directory and change to new one
const stack = shell.pushd('/path/to/directory');
console.log('Directory stack:', stack);
// Push without changing directory
shell.pushd('-n', '/another/path');
// Push current directory onto stack (no directory change)
shell.pushd();
// Navigate using stack positions
shell.pushd('+1'); // Rotate to second directory in stack
shell.pushd('-0'); // Move top of stack to currentPops a directory from the directory stack and optionally changes to it.
/**
* Pop directory from stack and optionally change to it
* @param options - Command options
* @param dir - Stack position to pop ('+N', '-N')
* @returns ShellString containing directory stack as array
*/
function popd(options?: string, dir?: string): ShellString;
function popd(): ShellString;Options:
-n: Don't change directory, just manipulate stackUsage Examples:
// Pop and change to previous directory
const stack = shell.popd();
console.log('Returned to:', shell.pwd().toString());
// Pop specific stack position
shell.popd('+1'); // Pop second directory from stack
// Pop without changing directory
shell.popd('-n');
// Pop from bottom of stack
shell.popd('-0');Displays the current directory stack with various formatting options.
/**
* Display directory stack
* @param options - Display options or stack position ('+N', '-N')
* @returns ShellString containing directory stack as array
*/
function dirs(options?: string): ShellString;
function dirs(position: string): ShellString; // '+N' or '-N'Options:
-c: Clear the directory stack-v: Verbose output with stack positions+N: Show Nth directory from left (0-indexed)-N: Show Nth directory from right (0-indexed)Usage Examples:
// Show current directory stack
const stack = shell.dirs();
console.log('Stack:', stack);
// Verbose display with positions
shell.dirs('-v');
// Show specific position
const topDir = shell.dirs('+0'); // Top of stack
const bottomDir = shell.dirs('-0'); // Bottom of stack
// Clear directory stack
shell.dirs('-c');
// Use in loops
const stackArray = shell.dirs();
stackArray.forEach((dir, index) => {
console.log(`${index}: ${dir}`);
});// Save current location, do work elsewhere, return
shell.pushd('/project/build');
shell.exec('make clean && make');
shell.popd(); // Return to original directory
// Navigate through multiple directories
shell.pushd('/logs');
const errors = shell.grep('ERROR', '*.log');
shell.pushd('/config');
const configs = shell.ls('*.conf');
shell.popd(); // Back to /logs
shell.popd(); // Back to original
// Complex navigation pattern
function processDirectories(dirs) {
dirs.forEach(dir => {
shell.pushd(dir);
shell.echo(`Processing ${shell.pwd()}`);
// Do work in each directory
shell.exec('npm test');
shell.popd();
});
}// Build pipeline with error handling
function buildProject() {
shell.echo('Starting build...');
if (shell.exec('npm install').code !== 0) {
shell.echo('Failed to install dependencies');
shell.exit(1);
}
if (shell.exec('npm run lint').code !== 0) {
shell.echo('Linting failed');
shell.exit(1);
}
if (shell.exec('npm test').code !== 0) {
shell.echo('Tests failed');
shell.exit(1);
}
if (shell.exec('npm run build').code !== 0) {
shell.echo('Build failed');
shell.exit(1);
}
shell.echo('Build completed successfully');
}
// Async command execution
function deployAsync() {
shell.exec('docker build -t myapp .', { async: true }, function(code, stdout, stderr) {
if (code === 0) {
shell.echo('Build successful, deploying...');
shell.exec('docker push myapp', { async: true }, function(code, stdout, stderr) {
if (code === 0) {
shell.echo('Deploy successful');
} else {
shell.echo('Deploy failed:', stderr);
}
});
} else {
shell.echo('Build failed:', stderr);
}
});
}
// Environment-specific execution
function runTests(environment) {
const envVars = {
...process.env,
NODE_ENV: environment,
TEST_DB_URL: `mongodb://localhost/test_${environment}`
};
const result = shell.exec('npm test', {
env: envVars,
silent: true
});
if (result.code === 0) {
shell.echo(`✓ Tests passed in ${environment} environment`);
} else {
shell.echo(`✗ Tests failed in ${environment} environment`);
shell.echo(result.stderr);
}
return result.code === 0;
}
// Command chaining with validation
function validateAndDeploy() {
// Check prerequisites
if (!shell.which('docker')) {
shell.echo('Docker is required but not installed');
shell.exit(1);
}
if (!shell.which('git')) {
shell.echo('Git is required but not installed');
shell.exit(1);
}
// Validate git status
const status = shell.exec('git status --porcelain', { silent: true });
if (status.stdout.trim()) {
shell.echo('Working directory is not clean');
shell.exit(1);
}
// Execute deployment
const commands = [
'git pull origin main',
'npm ci',
'npm run build',
'docker build -t app:latest .',
'docker push app:latest'
];
for (const cmd of commands) {
shell.echo(`Executing: ${cmd}`);
if (shell.exec(cmd).code !== 0) {
shell.echo(`Command failed: ${cmd}`);
shell.exit(1);
}
}
shell.echo('Deployment completed successfully');
}// Comprehensive error handling
function safeExec(command, options = {}) {
shell.echo(`Running: ${command}`);
const result = shell.exec(command, {
silent: true,
...options
});
if (result.code === 0) {
shell.echo(`✓ Success: ${command}`);
if (result.stdout && !options.silent) {
shell.echo(result.stdout);
}
} else {
shell.echo(`✗ Failed: ${command} (exit code: ${result.code})`);
if (result.stderr) {
shell.echo('Error output:', result.stderr);
}
if (options.fatal !== false) {
shell.exit(result.code);
}
}
return result;
}
// Usage
safeExec('npm test');
safeExec('optional-command', { fatal: false });Install with Tessl CLI
npx tessl i tessl/npm-shelljs