Portable Shell Commands for Node - cross-platform wrapper around ShellJS for npm package scripts
npx @tessl/cli install tessl/npm-shx@0.4.0shx is a wrapper around ShellJS Unix commands, providing an easy solution for simple Unix-like, cross-platform commands in npm package scripts. It enables running shell commands that work consistently across Windows, macOS, and Linux systems, solving the problem of platform-specific shell command differences in Node.js development workflows.
npm install shx --save-devFor programmatic usage:
import { shx } from 'shx';CommonJS:
const { shx } = require('shx/lib/shx');Note: shx is primarily designed as a CLI tool, but the core function can be imported directly from the package for programmatic use.
# Install globally for command line usage
npm install -g shx
# Basic file operations
shx ls # List files
shx mkdir build # Create directory
shx cp src/file.js build/ # Copy files
shx rm -rf build # Remove directory recursively
shx echo "Hello World" # Output text
# With options
shx --silent ls nonexistent # Suppress error output
shx --verbose cp file.js dest/ # Verbose logging
shx --negate test -d mydir # Negate exit codeMost common usage in package.json:
{
"scripts": {
"clean": "shx rm -rf build dist",
"prebuild": "shx mkdir -p build && shx cp -r src/* build/",
"postbuild": "shx echo \"Build complete!\"",
"test:cleanup": "shx rm -rf coverage && shx rm *.log"
}
}shx is a cross-platform CLI wrapper around ShellJS commands with several key architectural components:
cli.js): Handles command-line argument parsing and stdin detection, passes execution to the core shx functionshx.js): Main execution engine that validates commands, loads plugins, applies options, and executes ShellJS functionsconfig.js): Manages exit codes, command blocklists, pipe detection, and plugin loading configuration.shxrc.jsonThe architecture ensures that all ShellJS commands work consistently across Windows, macOS, and Linux by normalizing the execution environment and providing cross-platform path and glob handling.
The main shx command-line interface that wraps ShellJS commands with cross-platform compatibility.
// Binary entry point: lib/cli.js
// Usage: shx [options] <command> [args...]Supported Commands:
All ShellJS commands except: cd, pushd, popd, dirs, set, exit, exec, ShellString
Common Commands:
cp, mv, rm, mkdir, rmdir, ls, findcat, head, tail, grep, sed, sort, uniqtest, which, pwdechotrue, false (via plugin)Options that modify shx behavior across all commands:
// Global shx options (prefix with --)
interface ShxOptions {
// shx-specific options
version: boolean; // Display version information
help: boolean; // Show help text
negate: boolean; // Flip exit status (0→1, non-zero→0)
// ShellJS shell.config options (inherited)
silent: boolean; // Suppress error output
verbose: boolean; // Enable verbose logging
noglob: boolean; // Disable glob expansion
fatal: boolean; // Exit on first error (not supported in CLI)
// Command-specific options (passed through to ShellJS)
[key: string]: any; // Additional options passed to underlying ShellJS commands
}Core function for programmatic usage:
/**
* Execute shx command programmatically
* @param argv - Command line arguments in process.argv format
* @returns Exit code (0 for success, non-zero for errors)
*/
function shx(argv: string[]): number;Exit Codes:
const EXIT_CODES = {
SUCCESS: 0, // Successful execution
CMD_FAILED: 1, // Command execution failed
SHX_ERROR: 27 // shx-specific error (invalid command, etc.)
};Configuration file support for plugin loading:
// .shxrc.json format
interface ShxConfig {
plugins: string[]; // Array of plugin names to load
}Example .shxrc.json:
{
"plugins": ["shelljs-plugin-open", "custom-plugin"]
}Special regex conversion for Unix-like sed syntax:
# Unix-style sed syntax (converted internally)
shx sed "s/original/replacement/g" filename.txt
shx sed -i "s/find/replace/" file.txt
# Flags supported: g (global), i (case-insensitive)Important: Forward slashes / in patterns must be escaped as \/ in shell, or \\/ in package.json.
Automatic stdin processing for pipe-compatible commands:
# Commands that support piped input
echo "content" | shx grep "pattern"
cat file.txt | shx head -5
ls | shx sortPipe-compatible commands:
cat (minArgs: 1)grep (minArgs: 2)head (minArgs: 1)sed (minArgs: 2)sort (minArgs: 1)tail (minArgs: 1)uniq (minArgs: 1)Built-in and custom plugin support with automatic loading:
// Built-in true/false plugin (always loaded)
function shellTrue(): string; // Returns empty string, exit code 0
function shellFalse(): void; // Sets error state, exit code 1Plugin Loading System:
/**
* Plugin configuration loaded from .shxrc.json in current working directory
* Plugins are loaded via require() before command execution
*/
interface PluginConfig {
plugins: string[]; // Array of npm package names to require as plugins
}
/**
* Built-in plugin registration (example from true/false plugin)
* Uses ShellJS plugin system for command registration
*/
import plugin from 'shelljs/plugin';
plugin.register('true', shellTrue, {
allowGlobbing: false, // Disable glob expansion for this command
wrapOutput: true // Wrap output in ShellString object
});
plugin.register('false', shellFalse, {
allowGlobbing: false,
wrapOutput: true
});Plugin Loading Process:
.shxrc.json in current working directoryrequire() each plugin listed in the plugins arraytrue/false plugin is always loaded automaticallyDynamic help generation:
/**
* Generate help text with available commands and options
* @returns Formatted help string
*/
function help(): string;Output formatting and result handling:
/**
* Handle output formatting for ShellJS command results
* @param ret - Command result (string, object, or boolean)
*/
function printCmdRet(ret: any): void;
/**
* Determine if command should read from stdin
* @param args - Command arguments array
* @returns true if should read stdin, false otherwise
*/
function shouldReadStdin(args: string[]): boolean;
/**
* Convert Unix-style sed syntax to JavaScript RegExp for ShellJS
* @param args - Array of sed command arguments
* @returns Array with regex patterns converted to RegExp objects
* @throws Error for empty regex patterns
*/
function convertSedRegex(args: string[]): (string | RegExp)[];Core configuration values used throughout shx:
// Command blocklist - unsupported ShellJS commands
const CMD_BLOCKLIST: string[];
// Option blocklist - ShellJS options not supported in CLI
const OPTION_BLOCKLIST: string[];
// Configuration file name for plugin loading
const CONFIG_FILE: string; // '.shxrc.json'
// Pipe information for stdin-compatible commands
const SHELLJS_PIPE_INFO: {
[command: string]: { minArgs: number };
};{
"scripts": {
"clean": "shx rm -rf dist coverage *.log",
"prebuild": "npm run clean && shx mkdir -p dist/js dist/css",
"build": "shx cp -r src/* dist/ && shx echo \"Build complete\"",
"test": "shx rm -rf coverage && npm run test:unit",
"deploy": "shx test -d dist && shx cp dist/* deploy/ || shx echo \"Deploy failed\""
}
}{
"plugins": [
"shelljs-plugin-open",
"@company/custom-shell-plugin"
]
}# Using shell operators (handled by OS shell)
shx mkdir temp && shx cp file.txt temp/ && shx ls temp
shx rm -rf old || shx echo "Nothing to clean"
# In package.json (escape quotes)
"script": "shx mkdir build && shx echo \"Directory created\""Replace platform-specific commands:
{
"scripts": {
// Instead of: "clean": "rm -rf build" (Unix only)
"clean": "shx rm -rf build",
// Instead of: "copy": "cp -r src dest" (Unix only)
"copy": "shx cp -r src dest",
// Instead of: "mkdir": "mkdir -p build" (Unix only)
"mkdir": "shx mkdir -p build"
}
}Use double quotes for cross-platform glob support:
{
"scripts": {
"clean": "shx rm -rf \"build/**/*.js\" \"dist/*.css\"",
"copy": "shx cp \"src/**/*.ts\" build/"
}
}