Writing a `jjs` shebanged script that accepts just arguments

838 Views Asked by At

Supposedly jjs is the Java 8 version of nashorn, ready for shell-scripting. However when I write a file with execute permission as:

#!/usr/bin/jjs
arguments.forEach(function(v,i,a){print(v);});

Running it produces some not so ideal shell-scripting behavior:

$./file.js
$./file.js one two
java.io.IOException: one is not a file
$./file.js -- one two
one
two
$./file.js file.js -- one two # what were they thinking
one
two
one
two
$

So, I don't ever want this script I'm writing to allow for the arbitrary interpretation of a file after it runs, maybe I should use -- in the shebang like:

#!/usr/bin/jjs --
arguments.forEach(function(v,i,a){print(v);});

But this gets less useful:

$./file.js
jjs>^D
$./file.js one two
jjs>^D
$./file.js -- one two
jjs>

Yes, being dropped into a REPL prompt is exactly what I thought should not happen.

How am I supposed to make it possible to execute a script with arguments that are passed directly and not interpreted by jjs itself such that I can get behavior like:

$./file.js one two
one
two
$
2

There are 2 best solutions below

2
On BEST ANSWER

The example works as expected in the JDK 9 version of Nashorn. I'll take care of backporting the required patches so they can appear in one of the upcoming 8u releases.

Update: the required changes are backported to the 8u stream, but it is not clear at what point there will be a release. The early access releases of JDK 9 available from https://jdk9.java.net/download/ have the shebang feature, and also other extensions, such as piping support for the $EXEC builtin.

0
On

While waiting for the changes to be backported, I wrote a script to overcome the problem. My jvm is installed in the folder /usr/lib/jvm/jdk1.8.0_101, so I created the following script:

/usr/lib/jvm/jdk1.8.0_101/bin/jjs/bin/jjs-cp.sh:

#!/bin/bash
CP=
if [[ $1 = "--lib="* ]]; then
    LIB_FOLDERS=${1:6}
    shift

    LIB_FOLDERS=$(echo $LIB_FOLDERS | tr ":" "\n")
    for FOLDER in $LIB_FOLDERS; do
        if [[ $FOLDER = "!"* ]]; then
            CP="$CP:${FOLDER:1}"
        else
            if [ -d $FOLDER ]; then
                JARS=$(find "$FOLDER" -type l -o -type f -name "*.jar")
                for JAR in $JARS; do
                    CP="$CP:$JAR"
                done
            fi
        fi
    done
    if [ -n $CP ]; then
        CP=${CP:1}
    fi
fi
SCRIPT_FILE="$1"
shift
if [ -n $CP ]; then
    /usr/lib/jvm/jdk1.8.0_101/bin/jjs -cp "$CP" $SCRIPT_FILE -- $@
else
    /usr/lib/jvm/jdk1.8.0_101/bin/jjs $SCRIPT_FILE -- $@
fi

Then, in my test.js script I can write:

#!/usr/lib/jvm/jdk1.8.0_101/bin/jjs-cp.sh --lib=!.:<full path to classpath folder 1>:<full path to classpath folder 2>
var console = {
    log: function(msg) {
        java.lang.System.out.println(msg);
    }
};

console.log('Hello, world!');
arguments.forEach(console.log);

var MyClass = Java.type('com.acme.MyClass'); // load a class from a jar in the classpath
console.log(MyClass.class); // prints "class com.acme.MyClass"

And I can execute my script with this command line:

~$ ./test.js one two