biensure-nsh
v1.1.1
Published
A Node.js-based shell with REPL and script execution support.
Downloads
28
Readme
🐚 nsh — Node.js Shell
A REPL-powered Node.js shell that combines the flexibility of JavaScript with shell-like capabilities via ShellJS.
Supports CLI, .nsh scripts, argument passing, async functions, REPL history and auto-complete, persistent variables and ShellJS based plugins.
📦 Install
Install globally via NPM:
npm install -g biensure-nshTo run it locally (without installing globally):
npx nsh path/to/script.nsh🚀 Usage
Launch Interactive Shell
nshYou'll see a prompt like:
nsh:/your/current/directory >Try some shell commands:
ls();
cd('code');
pwd();These are available because ShellJS is loaded into the context of every .nsh script.
You can use any JavaScript too:
[1, 2, 3].map(x => x * 2);Why the big output object?
The reason why, after typing ls(), you see a very big object like this:
nsh:/home/user/directory > ls()
[
'LICENSE',
'README.md',
'node_modules',
'nsh.js',
'package-lock.json',
'package.json',
'test',
stdout: 'LICENSE\n' +
'README.md\n' +
'node_modules\n' +
'nsh.js\n' +
'package-lock.json\n' +
'package.json\n' +
'test\n',
stderr: null,
code: 0,
cat: [Function: bound ],
exec: [Function: bound ],
grep: [Function: bound ],
head: [Function: bound ],
sed: [Function: bound ],
sort: [Function: bound ],
tail: [Function: bound ],
to: [Function: bound ],
toEnd: [Function: bound ],
uniq: [Function: bound ]
]is because what you see is the output object from a ShellJS command.
As you can see it contains stdout, stderr, code and some sub functions exec(), .sort()...
These can be quite handy, look:
nsh:/home/user/directory > ls().sort()
[String: 'LICENSE\n' +
'node_modules\n' +
'nsh.js\n' +
'package-lock.json\n' +
'package.json\n' +
'README.md\n' +
'test\n'] {
...
}If don't want the big object and you only want the stdout just type:
console.log(ls().stdout);Alternatively to get short ouput with the ShellJS command echo(); simply add undefined;:
echo("hello"); undefined;Run a .nsh Script
nsh path/to/script.nshOr pass arguments:
nsh test/myscript.nsh hello world📁 Script Example
// test/example.nsh
console.log("Hello from nsh script!");
// Access CLI args
args.forEach((a, i) => console.log(`arg[${i}] = ${a}`));
// Use shelljs commands
console.log('Directory listing:');
console.log(ls().stdout);
// Async support
await new Promise(r => setTimeout(r, 1000));
console.log("Waited 1 second.");🧠 Passing Arguments to Scripts
Arguments passed on the command line are available as args:
nsh myscript.nsh foo bar// inside myscript.nsh
console.log(args); // ['foo', 'bar']⏳ Async/Await Support
All .nsh scripts run inside an async IIFE. So you can:
✅ Use await at top-level
✅ Perform file operations, HTTP requests, etc.
const { readFile } = require('fs/promises');
const content = await readFile('README.md', 'utf-8');
console.log(content);🧮 Persistent Variables
Variables defined in the REPL are persisted across commands during the session, just like in a regular JavaScript environment:
nsh
nsh:/home/user > var TESTVAR = 1;
nsh:/home/user > console.log(TESTVAR);
1
nsh:/home/user > echo(TESTVAR);
1
[String: '1\n'] {
stdout: '1\n',
stderr: null,
code: 0,
...
}These variables remain in memory until you exit the session. This makes it easy to store values, reuse them across shell and JS commands, and experiment interactively.
You can use both standard JavaScript functions and ShellJS utilities with your variables.
✨ Make .nsh Scripts Executable
To run .nsh scripts like regular shell scripts:
- Add a Shebang
At the very top of your .nsh script, add:
#!/usr/bin/env nsh- Make It Executable
Give it execute permissions:
chmod +x yourscript.nsh- Run It
./yourscript.nsh arg1 arg2It will behave just like a Bash or Python script — but powered by Node.js and ShellJS.
💼 Customized commands pwdl and lsl
For testing purpose the pwdl() and lsl() command were added:
// Added a console logged `pwd` helper command `pwdl()`
console.log(pwd().stdout);
// Added a console logged `ls` helper command `lsl()`
console.log(ls().stdout);This way the result was quite a bit shorter and directly effective.
Of courses you can wrap any ShellJS command in console.log() and choose to only log the error by adding .stderr instead of .stdout
🔌 Plugins
You can inject functionality into nsh via the plugin system of ShellJS.
Every plugin installed in ShellJS will be available within nsh.
Read the wiki about how to install, write and share plugins.
🧑💻 Author
Made by @biensurerodezee
MIT License
🛠️ Troubleshooting
- Maximum Call Stack Size Exceeded: This can happen if there's an infinite loop or recursion in your script. Make sure your scripts are not recursively calling themselves or running into circular dependencies.
- File Not Found: If you get an error saying
File not found, ensure the script path is correct and the file exists. - Command Not Found: Ensure you’ve correctly added ShellJS commands, read the plugin wiki.
🤝 Contributing
You can extend or contribute to nsh by:
- Sharing your-created.nsh scripts by adding them to the example/ folder and create a pull request.
- Creating ShellJS based plugins to add custom functionality.
- Opening an issue or submitting a pull request with any improvements.
✅ Test Coverage
The project includes a robust test suite (using Vitest) to validate:
- ✅ Version output
- ✅ Script execution with and without args
- ✅ Async/await handling
- ✅ Missing and invalid scripts
- ✅ Runtime error messages
- ✅ Script execution via REPL
- ✅ Shebang handling
- ✅ REPL prompt updates on cd
- ✅ REPL history load/save
Tests are located in nsh.test.js and cover both CLI and REPL functionality.
This should give you a full understanding of how to use, extend, or even set up nsh as your default shell :). Let me know if anything is unclear or if you need further improvements!
