CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-shelljs

Portable Unix shell commands for Node.js that provide cross-platform compatibility across Windows, Linux, and macOS.

Pending
Overview
Eval results
Files

process-management.mddocs/

Process Management

Commands for executing external processes, managing directory stacks, and controlling the shell environment and program flow.

Capabilities

exec - Execute External Commands

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' });

exit - Exit Process

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);
}

pushd - Push Directory

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 stack

Usage 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 current

popd - Pop Directory

Pops 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 stack

Usage 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');

dirs - Display Directory Stack

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}`);
});

Process Management Patterns

Directory Navigation Workflows

// 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();
  });
}

Command Execution Patterns

// 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');
}

Error Handling and Logging

// 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

docs

configuration.md

file-system.md

index.md

process-management.md

text-processing.md

tile.json