Как выполнить сценарий Java с JShell?

Учитывая, что Java 9 на нас, и мы можем наконец получить Java REPL с jshell Я надеялся, что есть способ добавить Шебанг в сценарий и иметь jshell интерпретировать это.

Я пытался создать test.jsh:

#!/usr/bin/env jshell -s
System.out.println("Hello World")
/exit

Однако это дает:

⚡ ./test.jsh
|  Error:
|  illegal character: '#'
|  #!/usr/bin/env jshell -s
|  ^
|  Error:
|  illegal start of expression
|  #!/usr/bin/env jshell -s
|    ^
Hello World

Оказывается, в OpenJDK есть запрос на усовершенствование https://bugs.openjdk.java.net/browse/JDK-8167440.

Есть ли другой способ сделать это?

3 ответа

Решение

Использование

//usr/bin/env jshell --show-version --execution local "$0" "$@"; exit $?

как первая строка test.jsh, test.jsh скрипт может выглядеть так:

//usr/bin/env jshell --show-version "$0" "$@"; exit $?
System.out.println("Hello World")
/exit

Опция командной строки --show-version не является обязательным, конечно, но дает немедленную обратную связь, что инструмент работает

Дополнительная опция командной строки --execution local предотвращает jshell породить другую ВМ. Это ускоряет время запуска, и если код вашего сценария создает исключение, локальная виртуальная машина завершает работу.

Обратитесь к выводу jshell --help а также jshell --help-extra для большего количества вариантов.

Оказывается, что с небольшой хитростью есть способ, хотя мне не удалось полностью подавить интерпретированные команды, но довольно близко к тому, что я хочу.

+ Изменить test.jsh чтобы:

#!/usr/bin/env sh
tail -n +4 "$0" | jshell -s "$@"
exit $?
System.out.println("Hello World")
/exit

Что дает нам:

⚡ ./test.jsh
-> System.out.println("Hello World")
Hello World
-> /exit

Ниже также работает; положить это вsomeScript.jsh файл и запустите его с ./someScript.jsh. Все аргументы, полученныеsomeScript.jsh будет идти к String[] args.

#!/home/gigi/.sdkman/candidates/java/current/bin/java --source 11

import java.util.Arrays;
import ro.go.adrhc.*; // example of using your classes, e.g. App below

public class X {
    public static void main(String[] args) {
        // do whatever you want here, e.g.:
        // System.out.println("Hello World");
        // or
        // use a class:
        // App.main(args);
        // e.g. from ro.go.adrhc package, by running:
        // CLASSPATH="/path-to-ro.go.adrhc-classes" ./someScript.jsh 
    }
}

Использование класса упаковки здесь X, является обязательной уловкой, чтобы это работало.
На основе https://blog.codefx.org/java/scripting-java-shebang/.

Вдохновленный steiny ответом, я придумал более общее решение

https://gist.github.com/ffissore/012d7e32a096fde5266f49038c93dcaf

По сути: jshell-wrapper удалит первую строку сценария (которая должна быть Шебанг) ​​и добавит /exit в конце сценария

Другие вопросы по тегам