npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nscript

v0.1.10

Published

Javascript powered shell scripts

Downloads

102

Readme

nscript

Write shell scripts like a bearded guru by unleashing your javascript skills!

nscript is a tool to write (sophisticated) shell scripts using javascript. It offers synchronous process spawning, command line argument parsing, parameter expansions, parallel execution, stream redirection, pipes; in short; anything that you liked about bash is now possible in javascript. nscript ships with a REPL as well.

nscript is already being used in for production systems at Mendix to power CI scripts for deployment, automated testing, saucelabs integration etc.

#!/usr/bin/nscript
module.exports = function(shell, echo, $beard) {
  if ($beard)
    echo("Awesome, you invoked this script with --beard. You probably are an unixian.");
  else if (shell.prompt("Do you have a mustache at least?","y") === "y")
    echo("Welcome, oh hairy ", shell.env.USER);
  else
    shell.exit(1, "Epic fail.");
};
$ ./unixian.js
Do you have a mustache at least? [y]: n
Epic fail.
$

More examples can be found in the examples directory.

Installing nscript

Install nscript using: npm install [-g] [--save[-dev]] nscript.

nscript relies on node-gyp, so if any errors occur upon installation, check its dependencies.

nscript primer

An nscript script is just a function exposed by a CommonJS module, preceded by a hashbang. The first parameter passes in the shell object, other parameternames are filled with wrapped executables with the same name. Use $flag or $$param as parameter names to make it possible for users to pass in arguments to your script.

The full API documentation

#!/usr/bin/nscript
module.exports = function(shell, grep, ls, cat, echo, gedit, sort, whoami) {

  // run a command
  // bash: echo hello world
  echo("hello","world")

  // use shell expansions
  // bash: echo src/*.js
  echo("lib/*.js")

  // or, to display all files recusively in lib/
  cat("lib/**/*.js")

  // prevent shell expansion
  // bash: echo 'lib/*.js'
  echo(["lib/*.js"])

  // obtain output
  var result = echo.get("hello","world")

  // nest commands
  // bash: echo hello `whoami`
  echo("hello", whoami.get())

  // check exit status
  // bash: echo hello world; echo $?
  var exitCode = echo.code("hello","world")

  // supress output
  // bash: ls > /dev/null
  ls.silent().run()

  // write output to file
  // bash: ls > dir.txt
  ls.write('test/tmp/dir.txt')

  // append output to file
  // bash: ls >> dir.txt
  ls.append('test/tmp/dir.txt')


  // pipe data into a process
  // bash: echo "pears\napples" | sort
  sort.input("pears\napples").run()

  // prompt for input
  // bash: echo -n "Your age? "; read $AGE
  var age = shell.prompt("Your age?")

  // start a process in the background
  // bash: gedit test/groceries.txt &
  gedit.detach("test/groceries.txt")

  // pipe processes
  // bash: cat test/groceries | grep '.js' | sort -i
  var sortedMilks = cat.args("test/groceries.txt").pipe(grep,"milk").pipe(sort,"-i").get()

  // read input from file and to file
  // bash: grep milk < groceries.txt > milksonly.txt
  grep.read('test/groceries.txt').args('milk').write('test/tmp/milksonly.txt')

  // spawn() provides fine grained input / output control append standard error to file
  // bash: ls *.js 2>> errors.txt | sort -u
  ls.args("lib/*.js").spawn().appendError('test/tmp/errors.txt').pipe(sort, "-u").wait()
}

Anatomy of a nscript script

The anatomy of script file can best be explained by looking at the following example script:

#!/usr/bin/nscript
module.exports = function(shell, $0, echo, whoami, $verbose) {
	if ($0)
		echo("Hello, ", $0)
	else
		echo("Hello, ", whoami.get())
}

The lines explained in detail:

  1. The first line is a so called shell bang to indicate unix based systems how to run this script. It is basically sugar for nscript thisfile.js. The line is further meaningless and ignored by node.
  2. A nscript script exposes a single function through module.exports. This is the function that will be interpreted and run by nscript. Of course it is possible to define many functions in the javascript file, but only one should be exposed.
  3. $0 is the first argument passed to this script. $verbose makes sure the --verbose command line flag is parsed automatically. See the documentation for more details about automatic parsing of command line flags.
  4. echo is passed into the function by nscript as an alias for the "echo" command. This is basically sugar for: var echo = shell.alias("echo");. By invoking the echo function, nscript starts the echo executable, and passes in the arguments provided to the function.
  5. whoami is an alias for the "whoami" command, which returns the name of the currently logged in user (on Unix systems). The .get() functions grabs the standard output of a command. In this cause, the output is passed to echo. (In shell scripts, this statement would be expressed as echo "Hello, " `whoami` .

Running nscripts without global nscript.

If nscript is installed as module of your node/npm project, you can also start nscript scripts without requiring a globally installed nscript:

#!/usr/bin/env node
require('nscript')(function(shell, echo, $0) {
  echo("Hello", $0);
});
$ ./greeter.js Michel
Hello Michel

Creating scripts with nscript --touch

To quickly start with a new script, you can use the convenient nscript --touch command, but of course you can also create script manually. nscript scripts are just plain javascript (commonjs module) files. The --touch command also makes sure the script will be executable. Use the additional --local if the script shouldn't rely on a globally installed nscript, but a node project dependency instead.

michel@miniub ~/demo $ nscript --touch myscript.js
Generating default script in 'myscript.js'
Marking script as executable: 'myscript.js'
michel@miniub ~/demo $ ./myscript.js
Hello, world!

Random questions

Starting nscripts programmatically

This option does not require nscript to be installed globally.

$ npm install nscript --save
require('nscript')(require('./script.js'));

Todo: working with Futures

(add example of async code + futures & nested nscript functions)

Future plans

  1. Windows support
  2. Minor improvements

Comparison to other tools.

Grunt

Grunt allows for high level declaritive writing of tasks. However, spawning new jobs, grabbing there output or using pipes and stdin/ stdout streams can not be done out of the box. Luckily, nscript can be used from within grunt scripts as well, so feel free to combine the best of both worlds! Or feel free to write a grunt-nscript plugin ;-).

ShellJS

ShellJS is an excellent tool and performs many typical build script tasks in a synchronous manner. Furthermore it behaves consistently on all platforms.

Nscript tries to be a more heavy duty tool and does not (yet) fully support windows. On the other hand, it supports more typical shell (for example bash) features. Some differences with ShellJS:

  • nscript allows for parallel execution of commands, even if they are invoked in a synchronously / blocking manner. See for example tests/shell.js testParallel
  • nscripts is very flexibile in input and output stream handling, it is possible to pipe streams, redirect to output (without buffering) or processing output streams in parallel. TODO: add test case for onLine(cb) + wait()
  • ShellJS offers a default implementation of several system commands. The advantage of this is that they work uniform on every platform, the disadvantage is that only a limited set of features is supported
  • nscript aims to help you to write fully fledged shell scripts and offers command line parsing out of the box
  • it is possible start processes in the background
  • nscript is more efficient in its approach to spawn processes synchronously; it doesn't block the main event loop
  • in short: nscript offers more fine grained process control, ShellJS offers less features, but the features that are offered are platform consistent and the api is a bit simpler.