picocli (一)选项与参数

1,544 阅读5分钟

[这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战]


一、实例

由于业务要求,需要提供一个cli命令行的工具。由于本人接触java比较多,于是采用了java以及picocli进行开发。从没接触过picocli,简单的记录一下相关的知识点。

开发环境

选择picocli有以下几个好处:

  • 支持注解,可以快速开发;
  • 支持打包成jar包;也支持通过Grallvmnative-image插件进行编译,不需要再依赖JDK就能够运行

开发环境:

  • 系统
    • win10
  • JDK选择
    • jdk8
    • graalvm
  • 第三方相关框架
    • okhttp
    • picocli-4.6.1

在记录这些资料的时候,picocli更新到4.6.1,所以引入对应版本的jar包即可。

相关maven配置

       <dependency>
           <groupId>info.picocli</groupId>
           <artifactId>picocli</artifactId>
           <version>4.6.1</version>
       </dependency>

示例

如下所示,定义了两个类CosimCommand以及CheckCommand,程序的执行入口是CosimCommandmain方法。

CosimCommand上标记了注解@CommandLine.Command用于告诉程序这是一个命令,相关属性如下:

  • name 命令名称
  • mixinStandardHelpOptions 是否支持-h等帮助命令
  • version 表示命令的版本
  • description
  • subcommands 表示子命令

相关源码:

//主命令
@CommandLine.Command(
        name = "cosim",
        mixinStandardHelpOptions=true,
        version = "1.0-SNAPSHOT",
        description = "cosim",
        subcommands = {
                CheckCommand.class
        }
)
public class CosimCommand implements Runnable{
    public static void main(String[] args) {
        int exitCode = new CommandLine(new CosimCommand()).execute(args);
        System.exit(exitCode);
    }
    @Override
    public void run() {
        System.out.println("The popular git command");
    }
}

//子命令

@CommandLine.Command(
        name = "check",
        mixinStandardHelpOptions=true,
        description = "子命令示例"
)
public class CheckCommand  implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("test");
        return null;
    }
}

执行

程序编写好后,可以通过IDEA执行,也可以通过jar包运行;在maven中添加以下构建配置进行打包:

    <build>
        <finalName>cosim-cli</finalName>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.5</version>
                <configuration>
                    // 这个配置用于导出依赖的jar包
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                            <addClasspath>true</addClasspath>
                    // 用于定义主类
                            <mainClass>com.simtek.cosimcloud.cli.CosimCommand</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>${project.basedir}/src/main/resources</directory>
            </resource>
        </resources>
    </build>
  • 添加maven配置
  • 打包后生成cosim-cli-jar-with-dependencies.jar
  • 执行命令:java -cp .\cosim-cli-jar-with-dependencies.jar com.simtek.cosimcloud.cli.CosimCommand check

注:CosimCommand这个类相当于cosim主命令,check是定义的子命令。

二、选项和参数

相关注解

picocli中常用的注解是@CommandLine.Command@CommandLine.Option@CommandLine.Parameters

@CommandLine.Command 用于定义命令,相关属性

  • name 用于定义命令名称
  • aliases 用于定义别名,允许多个
  • subcommands 用于定义一个或多个子命令
  • mixinStandardHelpOptions 启用–help
  • description 描述命令

@CommandLine.Option 用于定义命令选项(可选)

  • names 用于定义选项的一个或多个名称;Picocli 允许您使用任何您想要的选项名称。默认情况下,选项名称区分大小写,但这是可定制的。
  • paramLabel 参数分组
  • description 表示命令选项的描述
  • usageHelp
  • help
  • order 选项排序
  • required 标记选项是否必需

@CommandLine.Parameters 用于定义命令参数(必选)

  • paramLabel 参数分组
  • description 表示命令选项的描述

@CommandLine.ArgGroup:Picocli 4.0 引入了一个新的@ArgGroup注释及ArgGroupSpec;可用于定义:

  • 互斥选项
  • 必须同时出现的选项(从属选项)
  • 使用帮助消息中的选项部分
  • 重复复合参数

交互式(密码)选项【Interactive (Password) Options】

在 Java 6 或更高版本上运行时,picocli 将使用Console.readPasswordAPI,以便用户输入不会回显到控制台。从 picocli 4.6 开始,应用程序可以选择通过设置将用户输入回显到控制台echo = true,并设置prompt文本以控制在询问用户输入时在控制台上显示的内容。

@CommandLine.Command(
        name = "test",
        mixinStandardHelpOptions=true,
        description = "test"
)
public class TestCommand  implements Callable<Integer> {
    // 设置属性interactive = true
    @CommandLine.Option(names = {"-p", "--password"}, description = "Passphrase", interactive = true)
    char[] password;

    @Override
    public Integer call() throws Exception {
        System.out.println(password);
        return 1;
    }
}

执行后有以下的交互,会提示输入密码:

image.png

可选交互参数

默认情况下,交互选项会导致应用程序等待 stdin 上的输入。对于需要以交互方式和批处理模式运行的命令,如果该选项可以选择使用命令行中的参数,则非常有用。

使用arity设置可选:

@Option(names = "--user") 
String user;  // arity = "0..1" 允许调用命令时接受零到一个参数 

@Option(names = "--password", arity = "0..1", interactive = true) 
char[] password; 

使用以下输入,password字段将被初始化为”123”不提示用户输入:

--password 123 --user Joe 

但是,如果未指定密码,则会提示用户输入值。在下面的示例中,密码选项没有参数,因此将提示用户在控制台上输入一个值:

--password --user Joe

短 (POSIX) 选项

Picocli 支持POSIX 的短选项:一个或多个不带选项参数的单字符选项,后面可以跟最多一个带有选项参数的选项,可以分组在一个“-”分隔符后面。

class ClusteredShortOptions {
    @Option(names = "-a") boolean aaa;
    @Option(names = "-b") boolean bbb;
    @Option(names = "-c") boolean ccc;
    @Option(names = "-f") String  file;
}

<command> -abcfInputFile.txt
<command> -abcf=InputFile.txt
<command> -abc -f=InputFile.txt
<command> -ab -cf=InputFile.txt
<command> -a -b -c -fInputFile.txt
<command> -a -b -c -f InputFile.txt
<command> -a -b -c -f=InputFile.txt
...

布尔选项

布尔选项通常不需要参数:在命令行中指定选项名称就足够了。

class BooleanOptions {
    @Option(names = "-x")
    boolean x;
}


class BooleanOptionWithParameters {
    @Option(names = "-x", arity = "1", description = "1 mandatory parameter")
    boolean x;
    @Option(names = "-y", arity = "0..1", description = "min 0 and max 1 parameter")
    boolean y;
}

注:从 picocli 4.0 开始,布尔选项可以是negatable,即可选的;默认是false。

索引(index)

index属性(从0开始的整数)用于准确指定要捕获的参数;可以使用数组或集合字段捕获多个值。index属性接受范围值,因此像这样的注释会@Parameters(index=”2..4”)捕获索引 2、3 和 4 处的参数。范围值可以是开放式的。例如,@Parameters(index=”3..*”)捕获索引 3 及以上的所有参数。

class PositionalParameters {
    @Parameters(index = "0")    InetAddress host;
    @Parameters(index = "1")    int port;
    @Parameters(index = "2..*") File[] files;

    @Parameters(hidden = true)  // "hidden": don't show this parameter in usage help message
    List<String> allParameters; // no "index" attribute: captures _all_ arguments
}

省略索引:

  • 对于多个位置参数来说,省略index属性意味着该字段捕获所有位置参数(相当于index = “0..*”);
  • 对于单个位置参数,从 4.3 版开始,picocli 会根据同一命令中定义的其他位置参数自动分配索引。

注:从 picocli 2.0 开始,可以在命令行的任何位置指定位置参数,它们不再需要遵循选项。任何不是选项或子命令的命令行参数都被解释为位置参数。

双破折号 ( --)

当命令行参数之一是两个没有附加任何字符的破折号 (–) 时,picocli 会将所有后续参数解释为位置参数,甚至是与选项名称匹配的参数。