Top / Java / コマンドライン引数を制御するライブラリargs4j

コマンドライン引数を制御するライブラリargs4j ( http://args4j.kohsuke.org/ ) を使ってみます。 Javaのコマンドライン引数ってチェックするのとかなにげにメンドクサイですが、このライブラリを使うことで 必須チェックなどの自動化、args[i] の値をフィールドに自動でセット、usageの表示、 -u userid -p password みたいな指定を可能に、などをやってくれます。

Jenkinsの内部で Jenkins CLI でも使われている便利なライブラリです。

インストール

Mavenのpomだけ示しときますが、

<dependency>
  <groupId>args4j</groupId>
    <artifactId>args4j</artifactId>
    <version>2.33</version>
</dependency>

を追加しましょう

やってみる

たとえばこんな引数を持つ、コマンドラインプログラムがあったとします。パラメタに

 -U url [-p password] [-u userid]

みたいなパラメタをとるケースを考えます。ちなみにこの意味は

-U url は必須
-p password はオプション
-u userid もオプション

という意味です。

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; 

public class ProgramA {
    // こういうAnnotationをつける。nameはパラメタ名、aliasesは別名(の配列)、
    // metaVarはusageに表示される文字、requiredは必須かどうか、usageは説明
    @Option(name = "-U", aliases = {"--url" }, metaVar = "url", required = true, usage = "URL")
    private static String url;

    @Option(name = "-u", metaVar = "userid", usage = "Userid")
    private static String userid;

    @Option(name = "-p", metaVar = "password", usage = "Password")
    private static String password;

    // とりあえずは値を表示するだけ
    public void execute() {
        System.out.printf("url = %s \n", url);
        System.out.printf("userid = %s \n", userid);
        System.out.printf("password = %s \n", password);
     }
}

あらかじめこのようにパラメタにAnnotationをつけておきます。このプログラムを呼び出すクラスは下記の通り:

import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
 
public class BatchMain {
     public static void main(String[] args) {
        ProgramA main = new ProgramA();
        CmdLineParser parser = new CmdLineParser(main);
        try {
            parser.parseArgument(args);
        } catch (CmdLineException e) {
            System.out.println("usage:");
            parser.printSingleLineUsage(System.out);
            System.out.println();
            parser.printUsage(System.out);
            return;
        }
        main.execute();
    }
}

こんだけです。CmdLineParser?をかませるだけで、一通りのチェック処理とフィールドへの値のセット、usageの文字列構築などをやってくれます。必須パラメタなどがないと例外が発生し、

parser.printSingleLineUsage?(System.out); だと

 -U (--url) url [-p password] [-u userid]

と始めにしめしたusageが表示され、*1

parser.printUsage(System.out); だと

-U (--url) url : URL
-p password    : Password
-u userid      : Userid

と複数行に表示されます。なかなか便利ですね。

普通のパラメタをつかう

usage:

[param1] [others ...] -U (--url) url [-p password] [-u userid]

こんな感じのパラメタをとるケースを考えます。 -U 値 とかではない普通の引数指定ですね。0番目の引数は param1に 1..n番目の引数はothersに、それ以外は今まで通り、なんて指定です。

クラスに下記の通り@Argument を追加します。

public class ProgramA {

    @Option(name = "-U", aliases = {"--url" }, metaVar = "url", required = true, usage = "URL")
    private static String url;

    @Option(name = "-u", metaVar = "userid", usage = "Userid")
    private static String userid;

    @Option(name = "-p", metaVar = "password", usage = "Password")
    private static String password;

    // 普通の引数が入る。
    @Argument(index = 0, metaVar = "param1", required = false, usage = "Param1")
    private static String param1;

    // フィールドが配列なので1...n番目の引数が入る
    @Argument(index = 1, metaVar = "others", required = false, usage = "Others ...")
    private static String[] others;

    public void execute() {
        System.out.printf("url = %s \n", url);
        System.out.printf("userid = %s \n", userid);
        System.out.printf("password = %s \n", password);
        System.out.printf("param1 = %s \n", param1);
        if (others != null) {
            for (int i = 0; i < others.length; i++) {
                String other = others[i];
                System.out.printf("others[%d] = %s \n", i, other);
            }
        }
    }
}

これでOKです。usageでは

[param1] [others ...] -U (--url) url [-p password] [-u userid]

と出ますが、たとえば

aaa  -U http://www.masatom.in/  bbb  -u userA   ccc

などとわりとグッチャグチャに指定しても、

url = http://www.masatom.in/ 
userid = userA 
password = null 
param1 = aaa 
others[0] = bbb 
others[1] = ccc 

などとちゃんと処理してくれました。かなりステキです。

pom.xml について

蛇足ですがこういうバッチプログラムを実行するのにMavenが実行可能jarを作成してくれるとイイですよね。下記のpom.xmlを使って mvn clean package でjarを作成することで

java -jar target/Args4jSample-0.0.1-jar-with-dependencies.jar 
  aaa -U http://www.masatom.in/  bbb -u userA   ccc

などと実行可能になります。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Args4jSample</groupId>
  <artifactId>Args4jSample</artifactId>
  <version>0.0.1</version>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.2</version>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>batch.BatchMain</mainClass>
            </manifest>
            <manifestEntries>
              <Class-Path>.</Class-Path>
              <!-- これ↑でjarのある場所にクラスパスが通る。
                   たとえばlogback.xmlをjarとおなじディレクトリに置いておけば、参照してくれるようになる。 -->
            </manifestEntries>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>args4j</groupId>
      <artifactId>args4j</artifactId>
      <version>2.33</version>
    </dependency>
  </dependencies>
</project>
追記
mavenで作ったjarから実行すると、parser.printUsage(System.out); でヌルポが。。ちゃんと調べる時間がなくてよく分からない。。。とりあえずは、parser.printSingleLineUsage?(System.out); をつかっておけば問題なさそうな雰囲気。。

関連リンク


この記事は

選択肢 投票
おもしろかった 5  
そうでもない 2  
  • mavenで作ったjarから実行すると、parser.printUsage(System.out); でヌルポが。。ちゃんと調べる時間がなくてよく分からない。。。 -- きの? 2016-07-13 (水) 13:27:10

Top / Java / コマンドライン引数を制御するライブラリargs4j

現在のアクセス:8051


*1 --urlというaliasだけちょっと違うけど

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-12-06 (日) 16:56:09 (1226d)