クラスをちゃんと定義する
それでは、まずはJavaっぽく書いてみましょう。
public class Main { public static void main(String[] args) { System.out.println("Hello!"); } }
これを、任意のファイル名で保存します。たとえばhello。
実行するにはJava 11以降が必要です。みなさんすでにSDKMANを入れてると思うのでOracle OpenJDKの12.0.1を使ってみましょう。
$ sdk use java 12.0.1-open
では実行します
$ java --source 12 hello Hello!
実行できました!
これではちょっと面白くないので、先ほどのファイルの先頭にちょっとなにか追加しておきます。
#! /home/naoki/.sdkman/candidates/java/current/bin/java --source 12 public class Main { public static void main(String[] args) { System.out.println("Hello!"); } }
いわゆるShebangですね。
そして実行権限を付加
$ chmod +x hello
実行してみます。
$ ./hello Hello!
やった!
これはJEP 330: Launch Single-File Source-Code Programsに基づくもので、Java 11から導入されています。
Java11ではjavacせずにJavaファイルが実行できるようになる - きしだのHatena
これを「スクリプト」と呼ばないとき、現代のスクリプト言語も実行時にネイティブコードになったりするので、どの時点でコンパイルされればスクリプトなのか(スクリプトではないのか)という話になっておもしろいですね。
もっとスクリプトっぽく書く
さっきのは あまりにもJavaだったので、もっとJavaっぽくなく書いてみます。
System.out.println("Hello2!")
/exit
このファイルを任意のファイル名で保存します。たとえばhello2。行末のセミコロンも不要です。
では実行します。実行するためにはJava 9以降が必要です。すでに先ほどJava 12を導入してますね。
$ jshell hello2 Hello2!
やった!
もうちょっと複雑なコードを書いてみましょう。
import java.time.* var t = LocalDate.now() System.out.println(t.minusMonths(1) + " to " + t) System.out.println("Hello2!") /exit
実行してみます。
$ jshell hello2 2019-05-29 to 2019-06-29 Hello2!
だいぶスクリプトっぽい!
注意が必要なのは、ブロックの中ではセミコロンが必要というところです。
import java.time.* var t = LocalDate.now() System.out.println(t.minusMonths(1) + " to " + t) for (int i=0; i< 3; ++i) { System.out.println("Hello" + i); } /exit
実行してみます。
$ jshell hello2 2019-05-29 to 2019-06-29 Hello0 Hello1 Hello2
Shebangもやってみましょう。
#! /home/naoki/.sdkman/candidates/java/current/jshell import java.time.* var t = LocalDate.now() System.out.println(t.minusMonths(1) + " to " + t) for (int i=0; i< 3; ++i) { System.out.println("Hello" + i); } /exit
そして実行。
$ ./hello2 エラー: '#'は不正な文字です #! /home/naoki/.sdkman/candidates/java/current/bin/jshell ^ エラー: 式の開始が不正です #! /home/naoki/.sdkman/candidates/java/current/bin/jshell ^ エラー: 式の開始が不正です #! /home/naoki/.sdkman/candidates/java/current/bin/jshell ^ 2019-05-29 to 2019-06-29 Hello0 Hello1 Hello2
がーん!!
実行されは するけど、#!
の行もJavaとして解釈しようとするためにエラーになっちゃってますね。
これどうにかしないのかな?
7/1追記 BTSは立ってますね。 https://bugs.openjdk.java.net/browse/JDK-8167440
ちなみに、シェルスクリプトで1行目を無視するとかもありますが、OpenJDKソースを改変するなら、ここに
if (src.startsWith("#")) { return false; }
を入れると#
がコメントになってイケます。
https://github.com/openjdk/jdk/blob/master/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java#L1194