编写一个只接受参数的 `jjs` shebanged 脚本

Writing a `jjs` shebanged script that accepts just arguments

Supposedly jjs is the Java 8 version of nashorn, ready for shell-scripting。但是当我写一个具有执行权限的文件时:

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

运行 它会产生一些不太理想的 shell-脚本行为:

$./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
$

所以,我不想我写的这个脚本允许在文件运行后对其进行任意解释,也许我应该使用-- 在 shebang 喜欢:

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

但这有用:

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

是的,进入 REPL 提示正是我认为 应该发生的事情。

我应该如何使用直接传递的参数而不是由 jjs 本身解释的参数来执行脚本,这样我可以获得如下行为:

$./file.js one two
one
two
$

该示例在 JDK 9 版本的 Nashorn 中按预期工作。我将负责向后移植所需的补丁,以便它们可以出现在即将发布的 8u 版本中。

更新: 所需的更改已向后移植到 8u 流,但不清楚何时会发布。 https://jdk9.java.net/download/ 提供的 JDK 9 的早期访问版本具有 shebang 功能,以及其他扩展,例如对 $EXEC 内置函数的管道支持。

在等待更改向后移植时,我编写了一个脚本来解决这个问题。我的 jvm 安装在 /usr/lib/jvm/jdk1.8.0_101 文件夹中,所以我创建了以下脚本:

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

#!/bin/bash
CP=
if [[  = "--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=""
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

然后,在我的 test.js 脚本中我可以写:

#!/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"

然后我可以使用此命令行执行我的脚本:

~$ ./test.js one two