= Quick Guide //:author: Remko Popma //:email: rpopma@apache.org :revnumber: 4.6.1 :revdate: 2021-01-03 :toc: left :numbered: :toclevels: 1 // show little detail in the TOC, to make this document less intimidating :toc-title: Features :source-highlighter: rouge :rouge-languages: kotlin, groovy, scala :icons: font :imagesdir: images :linkattrs: :sectanchors: :docinfo: shared-head,private ifdef::env-github[] :caution-caption: :fire: :important-caption: :heavy_exclamation_mark: :note-caption: :information_source: endif::[] This is the Quick Guide. For more detail, see the full user manual at http://picocli.info[http://picocli.info]. == What is picocli Picocli is a one-file framework for creating Java command line applications with almost zero code. Picocli aims to be the easiest way to create rich command line applications that can run on and off the JVM. Picocli supports a variety of command line syntax styles including POSIX, GNU, MS-DOS and more. It generates highly customizable usage help messages with <>. Picocli-based applications can have link:autocomplete.html[command line TAB completion] showing available options, option parameters and subcommands, for any level of nested subcommands. Picocli-based applications can be ahead-of-time compiled to a image:https://www.graalvm.org/resources/img/logo-colored.svg[GraalVM] link:https://picocli.info/#_graalvm_native_image[native image], with extremely fast startup time and lower memory requirements, which can be distributed as a single executable file. Picocli link:https://picocli.info/#_generate_man_page_documentation[generates beautiful documentation] for your application (HTML, PDF and Unix man pages). .Example usage help message image:ExampleUsageANSI.png[Screenshot of usage help with Ansi codes enabled] [NOTE] ==== This document uses picocli's annotation API. For applications that cannot use the annotations, there is also a link:picocli-programmatic-api.html[programmatic API] for defining what options and positional parameters to expect, and for handling parse results. The programmatic API is not covered in this Quick Guide. ==== == [[_example_applications]][[Basic_example_ASCIIArt]]Basic example Below we show a small but fully functional example picocli-based command line application: `ASCIIArt`. `ASCIIArt` converts one or more arguments into ASCII art and prints them out. It can be used as follows: .Invoking the command ---- $ java -cp "myapp.jar;picocli-4.6.1.jar" ASCIIArt --font-size=9 Hello picocli # # # # # # # # # # # # # # *** # # **** #*** # **# **** **# # # ##### *** # # **** #*** # ** **** ** # # # # *#* # # * * # * # * * * * # # # # ** # # **** #*** # ** **** ** # # # # **# # # **** #*** # **# **** **# # # # * ---- [TIP] ==== The user manual has details on link:https://picocli.info/#_packaging_your_application[packaging your CLI application] so that users can invoke it simply with: ---- ASCIIArt --font-size=9 Hello picocli ---- ==== === ASCIIArt source code explained .ASCIIArt source code, shortened [source,java] ---- import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; // some exports omitted for the sake of brevity @Command(name = "ASCIIArt", version = "ASCIIArt 1.0", mixinStandardHelpOptions = true) // <2> public class ASCIIArt implements Runnable { // <1> @Option(names = { "-s", "--font-size" }, description = "Font size") // <3> int fontSize = 19; @Parameters(paramLabel = "", defaultValue = "Hello, picocli", // <4> description = "Words to be translated into ASCII art.") private String[] words = { "Hello,", "picocli" }; // <5> @Override public void run() { // <6> // The business logic of the command goes here... // In this case, code for generation of ASCII art graphics // (omitted for the sake of brevity). } public static void main(String[] args) { int exitCode = new CommandLine(new ASCIIArt()).execute(args); // <7> System.exit(exitCode); // <8> } } ---- Let's break it down into small steps: <1> Create a class that implements `Runnable` or `Callable`. This is your command. <2> Annotate the class with `@Command` and give it a name. The <> attribute adds `--help` and `--version` options to your application. <3> For each option in your application, add an `@Option`-annotated field to your command class. This example shows how you can give the options names and a description, there are many other attributes. <4> For each positional parameter, add a `@Parameters`-annotated field to your command class. <5> Picocli will convert the command line arguments to strongly typed values and will inject these values into the annotated fields. <6> Define your business logic in the `run` or `call` method of your class. This method is called after parsing is successfully completed. <7> In the `main` method of your class, use the `CommandLine.execute` method bootstrap your application. This will parse the command line, handle errors, handle requests for usage and version help, and invoke the business logic. <8> The `CommandLine.execute` method returns an exit code. Your application can call `System.exit` with this exit code to signal success or failure to the calling process. This is the basic skeleton of almost any picocli application. TIP: See the link:http://picocli.info/[reference manual] for more variations, like using the annotations on methods. Like any professional command line application, `ASCIIArt` has `--help` and `--version` options. The `--help` option shows the user how to use the application. Picocli generates this usage help message automatically: .Usage help message of our `ASCIIArt` command ---- $ ASCIIArt --help Usage: ASCIIArt [-hV] [-s=] [...] [...] Words to be translated into ASCII art. -s, --font-size= Font size -h, --help Show this help message and exit. -V, --version Print version information and exit. ---- === ASCIIArt execution: try it! [NOTE] ==== The content below shows the source code of the `ASCIIArt` example, embedded in the page using technology provided by https://www.jdoodle.com[jdoodle.com] that allows online execution. If the content is not displaying correctly, try opening https://www.jdoodle.com/embed/v0/2nfL?stdin=1&arg=1[this link] in a separate browser tab. ==== Execute the `ASCIIArt` example by clicking the blue `Execute` button below. ++++
++++ == [[Subcommands_Example_ISOCodeResolver]]Subcommands Example Below we show another small but fully functional example picocli-based command line application which explains the use of subcommands: `ISOCodeResolver`. This application has two subcommands, `language` and `country`, that resolve languages or country codes following the ISO standards (ISO-3166-1 for country codes, and ISO-639-1/639-2 for language codes). The application can be used as follows: .Resolving two letter language codes ---- $ java -cp "myapp.jar;picocli-4.6.1.jar" ISOCodeResolver language de cs en sd se de: German cs: Czech en: English sd: Sindhi se: Northern Sami ---- .Resolving two letter country codes ---- $ java -cp "myapp.jar;picocli-4.6.1.jar" ISOCodeResolver country cn fr th ro no CN: China FR: France TH: Thailand RO: Romania NO: Norway ---- [TIP] ==== The user manual has details on link:https://picocli.info/#_packaging_your_application[packaging your CLI application] so that users can invoke these commands simply with: ---- ISOCodeResolver language de cs en sd se ---- and ---- ISOCodeResolver country cn fr th ro no ---- ==== === ISOCodeResolver source code explained .Java [source,java,role="primary"] ---- import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Model.CommandSpec; import picocli.CommandLine.Parameters; import picocli.CommandLine.ParameterException; import picocli.CommandLine.Spec; import java.util.Locale; @Command(name = "ISOCodeResolver", subcommands = { SubcommandAsClass.class, CommandLine.HelpCommand.class }, // <2> description = "Resolves ISO country codes (ISO-3166-1) or language codes (ISO 639-1/-2)") public class ISOCodeResolver { // <1> @Spec CommandSpec spec; @Command(name = "country", description = "Resolves ISO country codes (ISO-3166-1)") // <3> void subCommandViaMethod( @Parameters(arity = "1..*", paramLabel = "", description = "country code(s) to be resolved") String[] countryCodes) { for (String code : countryCodes) { System.out.printf("%s: %s", code.toUpperCase(), new Locale("", code).getDisplayCountry()); } } public static void main(String[] args) { int exitCode = new CommandLine(new ISOCodeResolver()).execute(args); // <5> System.exit(exitCode); // <6> } } @Command(name = "language", description = "Resolves one ore more ISO language codes (ISO-639-1 or 639-2)") // <4> class SubcommandAsClass implements Runnable { @Parameters(arity = "1..*", paramLabel = "", description = "language code(s)") private String[] languageCodes; @Override public void run() { for (String code : languageCodes) { System.out.printf("%s: %s", code.toLowerCase(), new Locale(code).getDisplayLanguage()); } } } ---- .Kotlin [source,kotlin,role="secondary"] ---- import picocli.CommandLine import picocli.CommandLine.Model.CommandSpec import picocli.CommandLine.* import java.util.Locale import kotlin.system.exitProcess @Command( name = "ISOCodeResolver", subcommands = [SubcommandAsClass::class, HelpCommand::class], // <2> description = ["Resolves ISO country codes (ISO-3166-1) or language codes (ISO 639-1/-2)"]) class ISOCodeResolver { // <1> @Spec lateinit var spec: CommandSpec @Command(name = "country", description = ["Resolves ISO country codes (ISO-3166-1)"]) // <3> fun subCommandViaMethod(@Parameters(arity = "1..*", paramLabel = "", description = ["country code(s) to be resolved"]) countryCodes: Array) { for (code in countryCodes) { println("${code.toUpperCase()}: ${Locale("", code).displayCountry}") } } } fun main(args: Array) { val exitCode = CommandLine(ISOCodeResolver()).execute(*args) // <5> exitProcess(exitCode) // <6> } @Command(name = "language", description = ["Resolves ISO language codes (ISO-639-1/-2)"]) // <4> class SubcommandAsClass : Runnable { @Parameters(arity = "1..*", paramLabel = "", description = ["language code(s)"]) private lateinit var languageCodes: Array override fun run() { for (code in languageCodes) { println("${code.toLowerCase()}: ${Locale(code).displayLanguage}") } } } ---- .Scala [source,scala,role="secondary"] ---- import picocli.CommandLine import picocli.CommandLine.{Command, HelpCommand, Parameters} import picocli.CommandLine.Model.CommandSpec import java.util.Locale @Command(name = "ISOCodeResolver", subcommands = Array(classOf[SubcommandAsClass], classOf[HelpCommand]), // <2> description = Array("Resolves ISO country codes (ISO-3166-1) or language codes (ISO 639-1/-2)")) class ISOCodeResolver { // <1> val spec: CommandSpec = null @Command(name = "country", description = Array("Resolves ISO country codes (ISO-3166-1)")) // <3> def subCommandViaMethod(@Parameters(arity = "1..*", paramLabel = "", description = Array("country code(s) to be resolved")) countryCodes: Array[String]): Unit = { for (code <- countryCodes) { println(s"${code.toUpperCase()}: ".concat(new Locale("", code).getDisplayCountry)) } } } @Command(name = "language", description = Array("Resolves language codes (ISO-639-1/-2)")) // <4> class SubcommandAsClass extends Runnable { @Parameters(arity = "1..*", paramLabel = "", description = Array("language code(s)")) private val languageCodes = new Array[String](0) override def run(): Unit = { for (code <- languageCodes) { println(s"${code.toUpperCase()}: ".concat(new Locale(code).getDisplayLanguage)) } } } object ISOCodeResolver { def main(args: Array[String]): Unit = { val exitCode = new CommandLine(new ISOCodeResolver).execute(args: _*) // <5> System.exit(exitCode) // <6> } } ---- Let's break it down into small steps: <1> When the top-level command does not implement `Runnable` or `Callable`, users must specify a subcommand (subcommands become mandatory). This is optional: simply implement `Runnable` or `Callable` if the parent command can be executed by itself without subcommands in your application. <2> Annotate the class with `@Command` and give it a name. Note that we also specify the https://picocli.info/apidocs/picocli/CommandLine.HelpCommand.html[CommandLine.HelpCommand] class as subcommand in the annotation, to add the built-in `help` subcommand. <3> Custom subcommands can be added to the top-level command in two ways. The easiest way is to add a `@Command`-annotated method to the command class. For each option and positional parameter of the subcommand, add a method argument, and annotate these method arguments with the `@Option` or `@Parameters` annotation. In the example above, once the user invokes the subcommand `country`, the associated method `subCommandViaMethod` gets called. <4> In larger applications, it is common to create a separate `@Command`-annotated class for each subcommand. In the example above, the `SubcommandAsClass` class represents the `language` subcommand. Once the user invokes this subcommand, the overridden `run` method of this class is called. To register the subcommand, specify the subcommand class in the `subcommands` attribute of the `@Command` annotation of the parent command (subcommands = { SubcommandAsClass.class, ... } ❷). <5> In the `main` method of our `ISOCodeResolver` class, we use the `CommandLine.execute` method to bootstrap our application. This will parse the command line, handle errors, handle requests for usage and version help, and invoke the business logic of the associated subcommands. <6> The `CommandLine.execute` method returns an exit code. The application can call `System.exit` with this exit code to signal success or failure to the calling process. This is the basic skeleton of an picocli application with subcommands. TIP: See the link:https://picocli.info/#_subcommands/[Subcommands chapter] of the reference manual for more details and aspects of subcommands. In addition to the two user defined subcommands, the `ISOCodeResolver` app offers a `help` subcommand, which prints the usage help message to the console. Picocli generates this usage help message automatically: .Usage help message of our `ISOCodeResolver` command ---- $ ISOCodeResolver help Usage: ISOCodeResolver [COMMAND] Resolves ISO country codes (ISO-3166-1) or language codes (ISO-639-1/-2) Commands: help Displays help information about the specified command country Resolves ISO country codes (ISO-3166-1) language Resolves one ore more ISO language codes (ISO-639-1 or 639-2) ---- === ISOCodeResolver execution: try it! [NOTE] ==== The content below shows the source code of the `ISOCodeResolver` example, embedded in the page using technology provided by https://www.jdoodle.com[jdoodle.com] that allows online execution. If the content is not displaying correctly, try opening https://www.jdoodle.com/embed/v0/2mpW?stdin=1&arg=1[this link] in a separate browser tab. ==== Execute the `ISOCodeResolver` example by clicking the blue `Execute` button below. ++++
++++ == Options and Parameters Command line arguments can be separated into _options_ and _positional parameters_. Options have a name, positional parameters are usually the values that follow the options, but they may be mixed. image:OptionsAndParameters2.png[Example command with annotated @Option and @Parameters] Picocli has separate annotations for options and positional parameters. === Options An option must have one or more `names`. Option names commonly start with `-` or `--`, but picocli lets you use any option name you want. The below example shows options with one or more names, options that take an option parameter, and a <> option. [source,java] ---- class Tar { @Option(names = "-c", description = "create a new archive") boolean create; @Option(names = { "-f", "--file" }, paramLabel = "ARCHIVE", description = "the archive file") File archive; @Parameters(paramLabel = "FILE", description = "one ore more files to archive") File[] files; @Option(names = { "-h", "--help" }, usageHelp = true, description = "display a help message") private boolean helpRequested; } ---- Picocli matches the option names to set the field values. [source,java] ---- String[] args = { "-c", "--file", "result.tar", "file1.txt", "file2.txt" }; Tar tar = new Tar(); new CommandLine(tar).parseArgs(args); assert !tar.helpRequested; assert tar.create; assert tar.archive.equals(new File("result.tar")); assert Arrays.equals(tar.files, new File[] {new File("file1.txt"), new File("file2.txt")}); ---- Picocli supports http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02[POSIX clustered short options]: one or more single-character options without option-arguments, followed by at most one option with an option-argument, can be grouped behind one '`-`' dash. For example, for the `Tar` example above, the following command line invocations are equivalent: .Example commands with clustered short options ---- tar -c -f result.tar f1.txt f2.txt tar -cf result.tar f1.txt f2.txt tar -cfresult.tar f1.txt f2.txt ---- === Interactive (Password) Options For options and positional parameters marked as `interactive`, the user is prompted to enter a value on the console. When running on Java 6 or higher, picocli will use the https://docs.oracle.com/javase/8/docs/api/java/io/Console.html#readPassword-java.lang.String-java.lang.Object...-[`Console.readPassword`] API so that user input is not echoed to the console. The user manual has an link:http://picocli.info/#_interactive_password_options[example]. === Positional Parameters Any command line arguments that are not subcommands, options or option parameters are interpreted as positional parameters. Use the (zero-based) `index` attribute to specify exactly which parameters to capture. Omitting the `index` attribute means the field captures _all_ positional parameters. Array or collection fields can capture multiple values. The `index` attribute accepts _range_ values, so an annotation like `@Parameters(index = "2..4")` captures the arguments at index 2, 3 and 4. Range values can be _open-ended_. For example, `@Parameters(index = "3..*")` captures all arguments from index 3 and up. For example: [source,java] ---- class PositionalDemo { @Parameters(index = "0") InetAddress host; @Parameters(index = "1") int port; @Parameters(index = "2..*") List files; } ---- Picocli initializes fields with the values at the specified index in the arguments array. [source,java] ---- String[] args = { "localhost", "12345", "file1.txt", "file2.txt" }; PositionalDemo params = CommandLine.populateCommand(new PositionalDemo(), args); assert params.host.getHostName().equals("localhost"); assert params.port == 12345; assert params.files.equals(Arrays.asList(new File("file1.txt"), new File("file2.txt"))); ---- The user manual has more details about options and positional parameters, as well as the `--` http://picocli.info/#_double_dash_code_code[end-of-options delimiter] and parameter files (http://picocli.info/#AtFiles[`@`-files]). == Strongly Typed Everything When command line options and positional parameters are mapped to the annotated fields, the text value is converted to the type of the annotated field. === Type Conversion Out of the box, picocli can convert command line argument strings to a number of common data types. See the user manual for the full list of link:http://picocli.info/#_built_in_types[built-in types], but in general all primitive types and their Object equivalent, any enum, and common classes like `File`, `Date`, `URL`, `BigDecimal`, regex `Pattern` etc. can be used as is. Applications running on Java 7 can use `Path`, and on Java 8 the new `java.time` classes can be used. You can also use a link:http://picocli.info/#_custom_type_converters[custom type converter] to handle data types other than the above built-in ones. === Collections and Maps If an option or positional parameter can have multiple values, the field type must be an array, a `Collection` or a `Map`. Any `Collection` subclass like `List`, `Set`, or `Queue` can be used. A common requirement is to have options with key-value pairs similar to Java's system properties, like `-Dkey=value`. To achieve this, all you need to do is use a `Map` field. `Map` fields may have any type for their key and value as long as a <> is registered for both the key and the value type. Key and value types are inferred from the map's generic type parameters. For example: [source,java] ---- class MapDemo { @Option(names = {"-u", "--timeUnit"}); Map timeout; } ---- The following command line would result in four key-value entries in the map: [source,bash] ---- -uDAYS=3 -u HOURS=23 -u=MINUTES=59 --timeUnit=SECONDS=13 ---- == Required Arguments === Required Options Options can be marked `required` to make it mandatory for the user to specify them on the command line. When a required option is not specified, a `MissingParameterException` is thrown from the `parse` method. For example: [source, java] ---- @Option(names = "-n", required = true, description = "mandatory number") int number; ---- === Required Parameters Use the `arity` attribute to make `@Parameters` mandatory: [source, java] ---- @Parameters(arity = "1..*", descriptions = "at least one File") List files; ---- == Multiple Values Multi-valued options and positional parameters are annotated fields that can capture multiple values from the command line. === Repeated Options The simplest way to create a multi-valued option is to declare an annotated field whose type is an array, collection or a map. [source,java] ---- @Option(names = "-option") int[] values; ---- Users may specify the same option multiple times. For example: ---- -option 111 -option 222 -option 333 ---- Each value is appended to the array or collection. === Split Regex Options and parameters may also specify a `split` regular expression used to split each option parameter into smaller substrings. Each of these substrings is converted to the type of the collection or array. See <>. [source,java] ---- @Option(names = "-option", split = ",") int[] values; ---- A single command line argument like the following will be split up and three `int` values are added to the array: ---- -option 111,222,333 ---- === Arity Sometimes you want to define an option that requires more than one option parameter _for each option occurrence_ on the command line. The `arity` attribute lets you control exactly how many parameters to consume for each option occurrence. The `arity` attribute can specify an exact number of required parameters, or a _range_ with a minimum and a maximum number of parameters. The maximum can be an exact upper bound, or it can be `"*"` to denote _any number_ of parameters. For example: [source, java] ---- class ArityDemo { @Parameters(arity = "1..3", descriptions = "one to three Files") File[] files; @Option(names = "-f", arity = "2", description = "exactly two floating point numbers") double[] doubles; @Option(names = "-s", arity = "1..*", description = "at least one string") String[] strings; } ---- A `MissingParameterException` is thrown when fewer than the miminum number of parameters is specified on the command line. ==== Default Arity If no `arity` is specified, the number of parameters depends on the field's type. The user manual has more details on http://picocli.info/#_default_arity[arity]. == Help Options === Mixin Standard Help Options When the `mixinStandardHelpOptions` command attribute is set to `true`, picocli adds a <> to the command that adds <> and <> options to the command. For example: [source,java] ---- @Command(mixinStandardHelpOptions = true, version = "auto help demo - picocli 3.0") class AutoHelpDemo implements Runnable { @Option(names = "--option", description = "Some option.") String option; @Override public void run() { ... } } ---- The usage help message for the above example looks like this: ---- Usage:
[-hV] [--option=