JavaScript Shell Your JDK Contains Everything for ad hoc Programming

No Comments

You work on a Mac or Windows desktop and deploy to a Unix/Linux server?

You need a command line shell?

You are not an expert in all the different shells on all the different systems?

You answer some of the questions above with ‘yes’?

This blog entry may bring you some news, even if the facts for this are quite old, actually as old as Java 6, which will go out of service this November.

First Steps

With Java 6 Sun introduced the command jrunscript (it’s only part of the JDK, not the JRE).  Starting it, you see the prompt “js>” and a friendly blinking cursor. As a Linux user you may try “ls”, as a Windows user “dir”. Both commands don’t work. We are using a JavaScript shell, and the name of a function in JavaScript evaluates to a function object. You have to call the function: “ls()” or “dir()”. Both functions do the same – on all operating systems – they list the current directory content in the style of the Unix command “ls –l”.

In fact jrunscript is not much more than a wrapper around the Java scripting API [JSR223]. Each line you enter is treated as a JavaScript expression and evaluated. When there is a result (not null), toString() of that result is echoed. What makes it a shell is the set of predefined Java functions. The set consists of variations of the most common Unix commands, like “ls”, “cd”, “pwd” etc.. The full set is documented by Oracle, see [JRUNSCRIPT]. Some of the commands are beyond usual shell commands, e.g. you can convert an XML document to a DOM tree or execute an Xslt transformation.

So far we have used the interactive mode of jrunscript. Of course there is a batch mode, too: Option –f followed by a filename executes the file and terminates afterwards. This can be useful for automation, e.g. cron jobs. Compared to bash or cmd scripts, JavaScript has the advantage of operating system independence. Additionally, in nearly every Java (web) project you will find a guy who speaks JavaScript. Finding bash expertise may be more difficult.

Ad Hoc Programming

A programming language should be used for … programming! In the case of jrunscript, most of the time this is programming of throwaway one liners. Let’s assume the build directory has to be cleaned (and your build script misses a clean target). This can be done by find('.', '.*.class', rm). The first parameter of find is the start directory (here the current directory). The second is a regular expression for the filename (without path, here it matches all class files). The last is the most interesting: A callback which is called with the absolute filename of each matching file.

Callbacks in JavaScript can be function objects (just write the function name) or anonymous functions. The example above uses the built in function rm. An example with an anonymous function (lambda expression) follows; it finds all Java files where the absolute filename consists of more than 60 characters. You may need a similar function when you port your project to a limited operating system…

find('.', '.*.java', function(x) { if (x.toString().length() > 60) echo(x) })

There is no help function, when you need the documentation, use your browser or the source code. The call echo(rm) prints the JavaScript definition of the built in function rm. The complete source code of all functions is contained in tools.jar, file com/sun/tools/script/shell/init.js.

Each typed line is executed immediately, if it does not consist of one or more complete expressions, jrunscript answers with a syntax error. But there is a way to evaluate more than one line, use read() combined with eval: return eval(read('>', true)). The first parameter of read is the prompt, the second says you want to read more than one line. read() stops after you enter an empty line.

Batch Mode And Extending the Set of Builtin Commands

Beyond online execution of typed commands, jrunscript can be used in batch mode: Use the option –f followed by the script name. There can be more than one –f, so it is possible to execute more than one script with the same environment. This gives you the opportunity to combine batch and interactive mode. First, use –f with a script name, followed by –f with a minus sign instead of a file name.  The minus sign stands for standard input, so after execution of the script(s), it is possible to execute more expressions interactively.

This gives you the possibility to populate the JavaScript namespace with some of your own objects and/or functions. Remember the multiline problem from the last chapter? Add the line

function ml() { return eval(read('>', true)) }

to your startup script, and you can use your own function ml() whenever you want to enter expressions longer than one line.

Summary

jrunscript is quite different compared to other command line shells. The syntax requires more typing, e.g. functions have to be called with parentheses. In most shells you have to denote variables (by a $-sign), in jrunscript you have to quote strings.  As an advantage, the behavior is easier to understand compared to a Unix bash. There are no surprises caused by a space in a filename and there is nearly no quoting of special characters necessary.

How does jrunscript compare to a JavaScript console in your browser? Both use the same language, but the environment is quite different: In the browser, you have objects like doc or window, in jrunscript you have the Java bridge (see [JSGUIDE] for more details) and the full power of the classes in your jdk. It is even possible to put further jars to the classpath.

This article covers only a very small portion of what you can do with the JavaScript interpreter within the JDK. One feature not shown here is the Java bridge, which allows you use arbitrary Java classes within JavaScript.

A script shell is no replacement for build tools like ant, maven, or gradle, but it comes handy whenever you need a little bit of logic and don’t want to start your Java compiler. So maybe it will fill a niche in your life as developer.

One last word: When you are fed up with jrunscript: quit()

Author

Roger Butenuth

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Comment

Your email address will not be published. Required fields are marked *