@j-o-r/sh
v1.1.29
Published
Execute shell commands on Linux-based systems from javascript
Downloads
278
Maintainers
Readme
@j-o-r/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
SHcmd`` →SHDispatchfor.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:
AsyncTrackerviaasync_hooks. - Safe interpolation;
bashEscape; full JSDoc.
No runtime deps. ESM-only (ES2020+).
Quick Install
npm i @j-o-r/shUsage
Basics
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
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
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
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
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)
SH`vim`.options({ stdio: 'inherit' }).runSync();Testing
Full-featured tester with async support, error reporting, unresolved Promise detection.
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 anyAdvanced
SSH Example (interactive; use keys/sshpass for automation):
// 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
SHobject 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 viapgrep -P.
API
Full JSDoc in lib/*.js. Key exports:
| Utility | Description |
|---------|-------------|
| SHcmd`` | 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 for TS defs.
Development
npm run types # Generate types/
npm test # Run scenarios/sh.js
npm run release # Pack for publish
npm run publish # npm publishRepo: Codeberg | Issues: Codeberg Issues
License
Apache-2.0 © Jorrit Duin
