JavaでShell的に使えるコマンドラインツールを作る

Javaコマンドラインツールを作ったときのメモ.あえて Java でやる必要性があるかどうはか微妙ですが,まあなんとなく Java で書きたいこともあるでしょうということで.

コマンドラインパーサを使ってコマンドライン引数の管理する

基本的にコマンドはオプションありきなので,引数をパースしてオプションを解釈しなければなりません.コマンドラインパーサと呼ばれるようなライブラリを使えば,この辺を首尾よくできるようになります.例えば JCommander というオープンソースライブラリは,与えられた引数文字列→オブジェクトのようなマッピングをしてくれるので,かなり楽になります.「-f filename.txt」という文字列から File 型のオブジェクトに変換して保管してくれたりもします.

コマンドラインパーサには JCommander 以外にもいくつかあるので,まあこの辺は好みで選べばいいかと思います.今回は個人的に良さそうだと感じた JCommander を使っていきます.

Javaコマンドラインパーサをまとめてくれている人がいました↓.

CLI Comparison · remkop/picocli Wiki · GitHub

ダウンロード

ソースは以下

GitHub - cbeust/jcommander: Command line parsing framework for Java

Maven や Gradle を使っている場合は以下から.ちなみに現在,公式Docには Maven Repository から ver1.71 をダウンロードするような記述がありますが,1.71 は今管理されていないので 1.72 を指定します.プルリク送ろうと思ったらもうだいぶ前に出している人がいました(ザワ).

Maven Repository: com.beust » jcommander

基本機能

public class Args {
  @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
  private Integer verbose = 1;

  @Parameter(names = "-debug", description = "Debug mode")
  private boolean debug = false;

  @Parameter(names = "-out",
      description = "File name",
      converter = FileConverter.class)
  private File file;

  // あとgetterとか
}

こんな感じで引数クラスを定義して,オプション用のフィールドはアノテーションで指定します.文字列として渡される引数を File 型のインスタンスに変換したい場合などは,Converter クラスを作成してアノテーションの converter オプションに指定してあげます.

public static void main(String args[]) {
    Args argsInstance = new Args();
    JCommander.newBuilder()
            .addObject(argsInstance)
            .build()
            .parse(args);
    argsInstance.getFile();
}

あとは上のように Args 用のインスタンスを用意してパースメソッドに渡してあげるだけです.

詳細は以下の公式Docから

JCommander

成果物のjarファイルをコマンド的に使えるようにする

Java だとプログラムを書き終わったら jar ファイルとして出力するのが一般的だと思います.ただ,このプログラムを使うのにイチイチ以下のように書くのは面倒です.

java -jar hogehoge.jar -debug -out filename.txt

ので,この jar をコマンド化します.

コマンドライン

コマンドラインからだと以下でOKです.

(echo '#!/usr/bin/env java -jar'; cat hogehoge.jar) > hogehoge
chmod +x hogehoge

1行目に java -jar を指定した shebang,その後に jar を続けたファイルを用意し,実行権を付与しています. で,hogehoge を /usr/local/bin とかパスの通った場所に置くと,以下のように実行できます.

hogehoge -debug -out filename.txt

Gradleタスクで

この動作を Gradle のタスクとして書いている人がいましたので以下に貼っておきます.

gist.github.com