在 java shebang 脚本中加载库

Load library in a java shebang script

自 JDK-11 以来,我们有能力 运行 java 直接获取源代码。此代码

import org.apache.commons.codec.digest.Md5Crypt;

public class Oneliner {
  public static void main(String[] args){
    System.out.println(Md5Crypt.md5Crypt("ok".getBytes(), "$saltsalt"));
  }
}

可以是 运行 和

$ /usr/lib/jvm/jdk-11/bin/java --source 8 -cp /home/imaskar/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar jscript.java

但在 shell 脚本形式 (shebang)

#!/usr/lib/jvm/jdk-11/bin/java --source 8 --class-path /home/imaskar/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar

import org.apache.commons.codec.digest.Md5Crypt;

public class Oneliner {
  public static void main(String[] args){
    System.out.println(Md5Crypt.md5Crypt("ok".getBytes(), "$saltsalt"));
  }
}

我得到一个错误:

$ ./jscript.sh
Error: Could not find or load main class ..jscript.sh
Caused by: java.lang.ClassNotFoundException: //jscript/sh

问题出在第一行的 --class-path 参数。出于某种原因 --souce 参数通过,但 --class-path 没有。

你的 shebang 论点是错误的。

--class-path 需要在 --source

之前

它被提及 in the original JEP,但它相当深奥,并且分为几个部分...

以下将起作用。

#!/usr/lib/jvm/jdk-11/bin/java --class-path /home/imaskar/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar --source 8 

import org.apache.commons.codec.digest.Md5Crypt;

public class Oneliner {
  public static void main(String[] args){
    System.out.println(Md5Crypt.md5Crypt("ok".getBytes(), "$saltsalt"));
  }
}

我的版本如下

$ /usr/bin/java -version
java version "11" 2018-09-25
Java(TM) SE Runtime Environment 18.9 (build 11+28)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11+28, mixed mode)

$ cat kkkk.sh
#!/usr/bin/java --class-path /Users/steven/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar --source 8

import org.apache.commons.codec.digest.Md5Crypt;

public class Oneliner {
    public static void main(String[] args){
        System.out.println(Md5Crypt.md5Crypt("ok".getBytes(), "$saltsalt"));
    }
}

$ ./kkkk.sh
$saltsalt$PXysoX71YwjJOoKzgzTEg/

注意:根据我的示例,编写此答案时 (JDK 11 ea) --class-path 参数需要位于 --source 之前。现在 (JDK 15) 参数的顺序无关紧要,任何一个顺序都可以。

在 OpenJDK <= 11.0.7 中通常不起作用 。这是否是一个错误并得到修复尚不清楚。有一个打开的错误报告:

https://bugs.openjdk.java.net/browse/JDK-8242911

指定 --class-path 至少适用于 OpenJDK 12.0.214.0.1。 所以我假设对 Java 12 所做的一些改进解决了这个问题。

因此问题中的行应该有效,无需更改:

#!/usr/lib/jvm/jdk-11/bin/java --source 8 --class-path /home/imaskar/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar

关于其他答案和评论中提到的其他事情的一些注释:

  • --source 必须是第一个参数。在 shebang 文件中,第一行被视为 #!$COMMAND $ONE-SINGLE-ARGUMENT。所以 shell 不会用空格分隔 $ONE-SINGLE-ARGUMENT。因此,如果 Java 启动器以 --source 开头并进一步处理其他参数,则 Java 启动器将按空格拆分参数。
  • 我无法完全解释 muttonUp 的工作示例。我怀疑这与macOS的使用有关。也许使用过的 shell 已经分解了 shebang 参数。
  • 因此,此问题可能仅限于某些 shell。我已经用 Ubuntu 的 bashdash.
  • 测试了行为

如之前的回答所述,java 11:

中存在错误

https://bugs.openjdk.java.net/browse/JDK-8242911

我发现这个解决方法让我可以使用 class-path 参数:

#!/usr/bin/env -S java --class-path /path/mylib.jar --source 11

注意参数的顺序,如果--source--class-path之前则无效