UNPKG

@j-o-r/sh

Version:

Execute shell commands on Linux-based systems from javascript

161 lines (118 loc) 4.76 kB
# @j-o-r/sh   [![npm](https://img.shields.io/npm/v/@j-o-r/sh?logo=npm)](https://www.npmjs.com/package/@j-o-r/sh) [![License](https://img.shields.io/npm/license/@j-o-r/sh)](https://codeberg.org/duin/sh/src/branch/main/LICENSE) [![Codeberg](https://img.shields.io/badge/Codeberg-main-blue?logo=codeberg)](https://codeberg.org/duin/sh) Execute shell commands from JavaScript on Linux. ## Introduction `@j-o-r/sh` is a lightweight Node.js module for running shell commands with a clean, zx-inspired API. It fixes namespace pollution, adds **rolling timeouts** (reset on stdout/stderr), **no-shell mode** (`/usr/bin/env -S`), process tree kills, buffer limits (1MB default), and a built-in **Test** framework + **AsyncTracker** for leaks. **Key Features**: - Template tag `SH`cmd```SHDispatch` for `.options().run()`. - Global options: `SH.timeout = '5s'; SH.cwd = '/tmp';`. - Sync/async `run()`/`runSync()`; stdin payload; detached mode. - Utils: `sleep`, `retry`, `expBackoff`, `cd`, `parseArgs`, `userIn`, `readIn`. - Testing: `new Test().add('name', () => assert(...)).run()`. - Async leak detection: `AsyncTracker` via `async_hooks`. - Safe interpolation; `bashEscape`; full JSDoc. No runtime deps. ESM-only (ES2020+). ## Quick Install ```bash npm i @j-o-r/sh ``` ## Usage ### Basics ```js import { SH, cd, sleep } from '@j-o-r/sh'; cd('/tmp'); const out = await SH`ls -la`.run(); console.log(out); // Captured stdout (trimmed) ``` ### Chaining & Options ```js SH`curl -s ip.js.org` .options({ timeout: '2s', shell: false }) // No-shell: /usr/bin/env -S .run() .catch(e => console.error(e.message)); // "Command failed with code 1: ..." ``` ### Parallel & Context ```js import { within } from '@j-o-r/sh'; const results = await within(async () => Promise.all([ SH`sleep 1; echo ok`.run(), sleep('500ms'), SH`uname`.run() ])); ``` ### Retry & Backoff ```js import { retry, expBackoff } from '@j-o-r/sh'; try { const res = await retry(3, expBackoff('10s'), () => SH`curl -s unreachable`.run() ); } catch (e) { // Last error } ``` ### Interactive / Stdin ```js import { userIn, readIn } from '@j-o-r/sh'; // User prompt (abortable) const { input, abort } = userIn('Password: '); const pw = await input; // Piped stdin const out = await SH`grep secret`.run(await readIn()); ``` ### Vim / TTY (Sync) ```js SH`vim`.options({ stdio: 'inherit' }).runSync(); ``` ## Testing Full-featured tester with async support, error reporting, unresolved Promise detection. ```js import { Test, assert, jsType } from '@j-o-r/sh'; const t = new Test(true); // quiet: no console t.add('sync assert', () => assert.strictEqual(1 + 1, 2)); t.add('async', async () => { await sleep('100ms'); assert.strictEqual(jsType([]), 'Array'); }); const report = await t.run(); console.log(report); // { tests: 2, executed: 2, duration: 150, errors: 0 } t.unresolved(); // Logs leaks if any ``` ## Advanced - **SSH Example** (interactive; use keys/sshpass for automation): ```js // TTY/inherit for prompts SH`ssh user@host`.options({ stdio: 'inherit' }).runSync(); // Or sshpass: SH`sshpass -p pw ssh user@host`.run() ``` See `scenarios/` for full demos. - **CLI Args**: `parseArgs()``{ port: '8080', _: ['file'] }`. - **Global Defaults**: Set global options on the `SH` object to apply to all subsequent commands. These can be overridden per-command via `.options()`. Examples: - `SH.timeout = '5s';` – Default timeout for all runs. - `SH.cwd = '/tmp';` – Default working directory. - `SH.shell = false;` – Disable shell mode (uses `/usr/bin/env -S`). - `SH.maxBuffer = 1 * 1024 * 1024;` – Override default buffer limit (500kb) to 1MB per stream (stdout/stderr). Buffering captures output up to this limit; excess is truncated with markers. - **Kill Tree**: `dispatch.kill('SIGKILL')` → children via `pgrep -P`. ## API Full JSDoc in `lib/*.js`. Key exports: | Utility | Description | |---------|-------------| | `SH`cmd`` | Template → {@link SHDispatch} | | `cd(dir)` | `process.chdir()` | | `sleep('1s')` | Promise delay | | `retry(3, '1s', fn)` | Retry w/ delay/gen | | `userIn(prompt)` | `{ input: Promise, abort() }` | | `Test` | Test runner | | `AsyncTracker` | Async leak detector | | `parseArgs(argv)` | CLI parser | | `bashEscape(str)` | Shell-safe string | See [types/index.d.ts](types/index.d.ts) for TS defs. ## Development ```bash npm run types # Generate types/ npm test # Run scenarios/sh.js npm run release # Pack for publish npm run publish # npm publish ``` Repo: [Codeberg](https://codeberg.org/duin/sh) | Issues: [Codeberg Issues](https://codeberg.org/duin/sh/issues) ## License Apache-2.0 © [Jorrit Duin](mailto:jorrit.duin+sh@gmail.com)