22

我想看看两天前发布的 java 11 的一些新特性。 JEP 330声明我可以在不编译的情况下启动 Java-Source-Code-Program。它还应该支持 Shebang-Files 的使用。

因此,我编写了这个小 Hello-World 程序Test.java

#!/opt/java/jdk-11/bin/java --source 11

public class Test
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

下载了 JDK 11并将其解压缩到/opt/java. 因此,Shebang 本身正在工作。即执行/opt/java/jdk-11/bin/java --version给了我

openjdk 11 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

使Test.java可执行(使用chmod +x Test.java)后,执行失败。即./Test.java给我:

./Test.java:1: error: illegal character: '#'
#!/opt/java/jdk-11/bin/java --source 11
^
./Test.java:1: error: class, interface, or enum expected
#!/opt/java/jdk-11/bin/java --source 11
^
2 errors
error: compilation failed

一旦我从中删除 Shebang-LineTest.java并启动它,/opt/java/jdk-11/bin/java --source 11 Test.java 一切都像魅力一样工作,我得到了预期的输出:Hello World!

我的机器正在运行Ubuntu 17.04。我已经链接javac到 JDK 11 中的那个(即执行javac -versionjavac 11)。

4

3 回答 3

28

.java为了使java可执行文件忽略 shebang 行,文件名不能以结尾。您可以使用不同的扩展名,或者根本没有扩展名(这是他们在 JEP 示例中所做的,也是我推荐的)。

JEP 330(强调添加):

当启动器读取源文件时,如果该文件不是 Java 源文件(即它不是名称以 .java 结尾的文件)并且如果第一行以 #! 开头,则该行的内容为在确定要传递给编译器的源代码时,不包括第一个换行符将被忽略。出现在第一行之后的文件内容必须由 Java 语言规范版本中第 7.3 节定义的有效 CompilationUnit 组成,该版本适用于 --source 选项中给出的平台版本(如果存在),或用于运行程序的平台版本(如果 --source 选项不存在)。

它不需要专门以“.sh”结尾;此外,这可能会产生误导,因为该文件实际上不是 shell 脚本。

于 2018-09-27T19:05:51.533 回答
8

一些试验和错误给了我正确的解决方案。.java导致这些问题的是文件扩展名。

即,如果我将文件重命名为Test.sh一切正常。

这是一个完整的 Hello-World-Shebang-Example:

创建一个包含以下Test.sh内容的文件

#!/opt/java/jdk-11/bin/java --source 11

public class Test
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

使其可执行(即chmod +x Test.sh)。

最后但并非最不重要的是使用./Test.sh

于 2018-09-27T06:16:24.920 回答
2

根据您链接到的 JEP(请参阅shebang 文件部分),shebang 文件将用于启动 java 进程,而不是用作 java 的参数:

使用源文件模式调用 Java 启动器的 shebang 文件必须以以下内容开头:

#!/path/to/java --source version

例如,我们可以获取“Hello World”程序的源代码,并将其放在名为 hello 的文件中,在 #!/path/to/java --source 10 的初始行之后,然后将该文件标记为可执行文件。然后,如果文件在当前目录中,我们可以执行它:

$ ./hello

换句话说,您想要做的是使Test.java可执行。您还必须重命名它,因为当它被命名为 *.java 时,它不能作为 shebang 和剥离第一行。

$ move Test.java test
$ chmod +x test
$ ./test 

这将启动 shebang 处理器,它将剥离第一行并将脚本的其余部分传递给 /path/to/java,Java 将编译脚本并运行 main 方法。

于 2018-09-27T06:22:58.920 回答