Write shell scripts like a bearded guru by unleashing your javascript skills!
MIT License
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.
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
primerAn 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()
}
nscript
scriptThe 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:
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.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.$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.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.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`
.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
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!
This option does not require nscript
to be installed globally.
$ npm install nscript --save
require('nscript')(require('./script.js'));
(add example of async code + futures & nested nscript functions)
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 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:
tests/shell.js testParallel