Como analiso argumentos de linha de comando em Java?


586

Qual é uma boa maneira de analisar argumentos de linha de comando em Java?


4
Veja args4j e um exemplo detalhado como usá-lo: martin-thoma.com/how-to-parse-command-line-arguments-in-java
Martin Thoma

Parece que estou muito atrasado para esta festa, mas escrevi um manipulador de argumentos de linha de comando para Java e o coloquei no GitHub: MainArgsHandler . Quanto ao encadeamento ser fechado, acho que é um encadeamento muito útil, mas possivelmente deve ser migrado para o site Stack Exchange Programmers para discussão geral sobre programação.
Bobulous

@RedGlyph - Parece que o SO / SE precisa simplificar suas regras. A questão deveria ter sido: How to parse java command line arguments?. Mas ninguém realmente deseja escrever código para fazer isso, mas use uma ferramenta. Mas procura de ferramentas e os gostos não é construtiva :(
AlikElzin-Kilaka

6
Votou para reabrir. @AlikElzin: De fato, eles precisam revisar seu processo de moderação. Suspeito que exista um distintivo para o fechamento de tantas perguntas e que esteja atraindo o desejo de moderadores a serem excessivamente zelosos.
RedGlyph

8
Esta pergunta é um honeypot para respostas ruins / de uma linha e recomendações de ferramentas. Deve permanecer fechado.
JAL

Respostas:


405

Verifique estes:

Ou faça o seu:


Por exemplo, é assim que você usa commons-clipara analisar 2 argumentos de sequência:

import org.apache.commons.cli.*;

public class Main {


    public static void main(String[] args) throws Exception {

        Options options = new Options();

        Option input = new Option("i", "input", true, "input file path");
        input.setRequired(true);
        options.addOption(input);

        Option output = new Option("o", "output", true, "output file");
        output.setRequired(true);
        options.addOption(output);

        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        CommandLine cmd;

        try {
            cmd = parser.parse(options, args);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
            formatter.printHelp("utility-name", options);

            System.exit(1);
        }

        String inputFilePath = cmd.getOptionValue("input");
        String outputFilePath = cmd.getOptionValue("output");

        System.out.println(inputFilePath);
        System.out.println(outputFilePath);

    }

}

uso da linha de comando:

$> java -jar target/my-utility.jar -i asd                                                                                       
Missing required option: o

usage: utility-name
 -i,--input <arg>    input file path
 -o,--output <arg>   output file

40
Observe que, diferentemente de muitas outras bibliotecas do Apache, o Apache CLI não tem dependências.
Vladimir Dyuzhev

9
A única desvantagem de muitos projetos apache-commons é que eles recebem cada vez menos confirmações e acabam sendo obsoletos.
Brett Ryan,

4
Aqui está a página "Cenários de uso" para o projeto CLI do Apache, detalhando como começar a usá-lo rapidamente: commons.apache.org/cli/usage.html
Brad Parks

Suponho que não exista um exatamente como o Args4J / JCommander, exceto onde você define uma interface e anota os métodos? Eu nunca fui capaz de gostar de aulas que "assustadoramente inicializam" campos particulares ...
Trejkaz

5
@RemkoPopma, sua biblioteca de picocli está ótima e muito obrigado por fazê-lo. Mas considero o que você está fazendo aqui e em outras postagens (edite as respostas aceitas e promova sua biblioteca no topo dela, mesmo sem revelar que é uma edição que não é do autor original da postagem e é sua biblioteca) um abuso horrível e horrível de seus poderes de moderação. Sinalizando isso para outros mods.
Alexander Malakhov

312

Dê uma olhada no JCommander mais recente .

Eu criei. É um prazer receber perguntas ou solicitações de recursos.


7
Que bom que você gosta do JCommander :-) Eu não queria adicionar muita semântica à forma como os sinalizadores são tratados; portanto, você só precisa adicionar sinônimos nas anotações usadas: @Parameter (names = {"-h", "- -help "}) Eu pensei que era um compromisso razoável.
Cedric Beust

14
Ótima ferramenta. Poderoso, flexível e você não precisa lidar com os analisadores de opções tradicionais e irritantes.
IanGilham

3
Sim, acho que eu teria escrito meu próprio analisador de argumentos de linha de comando exatamente da mesma maneira que você escreveu o JCommander. Ótimo trabalho.
SRG

9
@CedricBeust, esta é uma biblioteca brilhante, muito obrigado. Como podemos definir nossas próprias classes Args, que podem ser transmitidas sem nenhuma dependência de uma classe de bibliotecas, torna-a extremamente flexível.
Brett Ryan

2
sopra a concorrência fora da água!
Marcus Junius Brutus

235

7
@ Ben Flynn hehe, existem algumas rodas em forma bastante surpreendentes e interessantes lá. Eu acho que é uma maneira inofensiva de mostrar que há muito mais do que uma maneira de fazê-lo!
Lexicalscope

14
Observo que o autor do JOpt Simple mantém uma lista muito semelhante! O que precisamos de texto é transformar essas listas em uma tabela, listando recursos e pontos de interesse, para que nós, usuários pobres, possamos fazer uma escolha informada.
Tom Anderson

1
Eu criei o Rop - github.com/ryenus/rop , que apresenta uma solução baseada em anotação que você declara comandos e opções por meio de classes e campos simples, praticamente uma maneira declarativa de criar analisadores de linha de comando. ele pode criar aplicativos como Git (cmd único) ou Maven (cmd).
Ryenus

8
A maioria dos projetos listados é essencialmente abandonware. Depois de ler a lista, eu diria que os grandes rebatedores, que são ativamente mantidos e populares, parecem commons-cli, jcommander, args4j, jopt-simple e picocli. Desculpas aos autores de coisas como argparse4j e cli-parser - eu tive que fazer uma classificação um tanto arbitrária e escolhi uma das cinco principais, claramente outros projetos da lista são populares e ainda estão em desenvolvimento ativo também.
George Hawkins

2
Desafio alguém a incluir a data da última versão estável de cada analisador.
Sledge

50

É 2020, hora de fazer melhor que o Commons CLI ... :-)

Você deve criar seu próprio analisador de linha de comando Java ou usar uma biblioteca?

Muitos aplicativos pequenos do tipo utilitário provavelmente rolam sua própria análise de linha de comando para evitar a dependência externa adicional. picocli pode ser uma alternativa interessante.

Picocli é uma biblioteca e estrutura modernas para criar aplicativos de linha de comando poderosos, fáceis de usar e habilitados para GraalVM com facilidade. Ele vive em um arquivo de origem e, portanto, os aplicativos podem incluí-lo como fonte para evitar adicionar uma dependência.

Ele suporta cores, preenchimento automático, subcomandos e muito mais. Escrito em Java, utilizável a partir de Groovy, Kotlin, Scala, etc.

Ajuda de uso mínimo com cores ANSI

Recursos:

  • Baseado em anotação: declarativo , evita duplicação e expressa a intenção do programador
  • Conveniente: analise a entrada do usuário e execute sua lógica de negócios com uma linha de código
  • Tudo fortemente digitado - opções de linha de comando e parâmetros posicionais
  • Opções curtas em cluster do POSIX ( <command> -xvfInputFileassim como <command> -x -v -f InputFile)
  • Controle refinado : um modelo de aridade que permite um número mínimo, máximo e variável de parâmetros, por exemplo "1..*","3..5"
  • Subcomandos (podem ser aninhados em profundidade arbitrária)
  • Rico em recursos : grupos de argumentos composíveis, argumentos entre aspas divididos, subcomandos repetíveis e muito mais
  • Fácil de usar : a mensagem de ajuda do uso usa cores para contrastar elementos importantes, como nomes de opções do restante do uso, para reduzir a carga cognitiva no usuário
  • Distribua seu aplicativo como uma imagem nativa do GraalVM
  • Funciona com Java 5 e superior
  • Documentação extensa e meticulosa

A mensagem de ajuda de uso é fácil de personalizar com anotações (sem programação). Por exemplo:

Mensagem de ajuda de uso estendido( fonte )

Não resisti em adicionar mais uma captura de tela para mostrar que mensagens de ajuda de uso são possíveis. A ajuda de uso é o rosto do seu aplicativo, portanto, seja criativo e divirta-se!

demonstração picocli

Disclaimer: Eu criei picocli. Comentários ou perguntas muito bem-vindos.


5
Gênio puro! É uma pena que esta resposta esteja enterrada no fundo. A CLI do Apache Commons é detalhada, com erros e não é atualizada há muito tempo. E não quero usar o analisador de CLI do Google porque não quero anúncios direcionados com base no meu histórico de uso de argumentos da linha de comando. Mas parece um pouco mais detalhado do que picocli de qualquer maneira.
Pete

2
Eu segundo @Pete aqui ... Examinei a lista acima, que foi uma completa perda de tempo com isso enterrado no fundo. Essa deve ser a melhor resposta em uma milha. Bom trabalho! Meus requisitos não puderam ser cobertos pelo apache CLI ou pela maioria desses outros analisadores. Eles eram desafiadores mesmo para picocli, mas era capaz de me dar a coisa mais próxima da sintaxe / comportamento que eu queria e era flexível o suficiente para invadir o que eu realmente precisava. Como um bônus, é ótimo graças ao material ANSI.
Shai Almog

@ShaiAlmog A resposta mais votada tem 10 anos e está desatualizada. Concordo que recomendar o CLI do Commons em 2019 é um IMHO enganador. Considere reescrever a resposta principal para torná-la mais atualizada.
Remko Popma 02/10/19

Vejo que já tentou isso, eu não acho que isso vai funcionar para mim também ... Se você teria escolhido um nome como 1Picoli poderíamos ter resolvido o 3º resposta alfabeticamente ;-)
Shai Almog

Acho que a razão pela qual minha alteração foi revertida é que não divulguei minha afiliação (sou o autor). Outras pessoas não devem ter esse problema.
Remko Popma

23

Eu usei o JOpt e achei bastante útil: http://jopt-simple.sourceforge.net/

A primeira página também fornece uma lista de cerca de 8 bibliotecas alternativas, verifique-as e escolha a que melhor se adapta às suas necessidades.


21

Alguém me indicou args4j recentemente, que é baseado em anotação. Eu realmente gosto!


1
+1 para Args4J! Extremamente amigável, flexível e compreensível. Eu acho que deveria ser a biblioteca padrão para a criação de aplicativos Java CLI.
Zearin 18/07/2013

É ótimo que ele possa lidar com impressões de uso desordenadas (classificadas por ordem de campo), que o JCommander não pode e é mais flexível.
Daniel Hári

@ DanielHári Apenas para informação, essa funcionalidade foi adicionada ao JCommander (em algum momento do final de fevereiro de 2017).
19419 Nathan

9

Esta é a biblioteca de análise de linha de comando do Google de código aberto, como parte do projeto Bazel. Pessoalmente, acho que é o melhor por aí e muito mais fácil que o Apache CLI.

https://github.com/pcj/google-options

Instalação

Bazel

maven_jar(
    name = "com_github_pcj_google_options",
    artifact = "com.github.pcj:google-options:jar:1.0.0",
    sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)

Gradle

dependencies {
  compile 'com.github.pcj:google-options:1.0.0'
}

Maven

<dependency>
  <groupId>com.github.pcj</groupId>
  <artifactId>google-options</artifactId>
  <version>1.0.0</version>
</dependency>

Uso

Crie uma classe que estenda OptionsBasee defina seu @Option(s).

package example;

import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;

import java.util.List;

/**
 * Command-line options definition for example server.
 */
public class ServerOptions extends OptionsBase {

  @Option(
      name = "help",
      abbrev = 'h',
      help = "Prints usage info.",
      defaultValue = "true"
    )
  public boolean help;

  @Option(
      name = "host",
      abbrev = 'o',
      help = "The server host.",
      category = "startup",
      defaultValue = ""
  )
  public String host;

  @Option(
    name = "port",
    abbrev = 'p',
    help = "The server port.",
    category = "startup",
    defaultValue = "8080"
    )
    public int port;

  @Option(
    name = "dir",
    abbrev = 'd',
    help = "Name of directory to serve static files.",
    category = "startup",
    allowMultiple = true,
    defaultValue = ""
    )
    public List<String> dirs;

}

Analise os argumentos e use-os.

package example;

import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;

public class Server {

  public static void main(String[] args) {
    OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
    parser.parseAndExitUponError(args);
    ServerOptions options = parser.getOptions(ServerOptions.class);
    if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
      printUsage(parser);
      return;
    }

    System.out.format("Starting server at %s:%d...\n", options.host, options.port);
    for (String dirname : options.dirs) {
      System.out.format("\\--> Serving static files at <%s>\n", dirname);
    }
  }

  private static void printUsage(OptionsParser parser) {
    System.out.println("Usage: java -jar server.jar OPTIONS");
    System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
                                              OptionsParser.HelpVerbosity.LONG));
  }

}

https://github.com/pcj/google-options


Oi Paul. Quando leio sua resposta ou a documentação do seu projeto, não faço ideia de que tipo de linha de comando ele pode lidar. Por exemplo, você pode fornecer algo parecido myexecutable -c file.json -d 42 --outdir ./out. E eu não vejo como você define as opções de descrição curta / longa / ... Cheers
olibre



7

Eu sei que a maioria das pessoas aqui encontrará 10 milhões de razões pelas quais elas não gostam do meu jeito, mas deixa pra lá. Eu gosto de manter as coisas simples, então apenas separo a chave do valor usando um '=' e as armazeno em um HashMap como este:

Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
    String[] parts = arg.split("=");
    argsMap.put(parts[0], parts[1]);
} 

Você sempre pode manter uma lista com os argumentos que espera, para ajudar o usuário caso ele se esqueça de um argumento ou use um errado ... No entanto, se você deseja muitos recursos, esta solução não é para você.


7

Talvez estes






4

Se você já estiver usando o Spring Boot, a análise de argumentos sairá da caixa.

Se você deseja executar algo após a inicialização, implemente a ApplicationRunnerinterface:

@SpringBootApplication
public class Application implements ApplicationRunner {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

  @Override
  public void run(ApplicationArguments args) {
    args.containsOption("my-flag-option"); // test if --my-flag-option was set
    args.getOptionValues("my-option");     // returns values of --my-option=value1 --my-option=value2 
    args.getOptionNames();                 // returns a list of all available options
    // do something with your args
  }
}

Seu runmétodo será chamado depois que o contexto for iniciado com êxito.

Se você precisar acessar os argumentos antes de iniciar o contexto do aplicativo, basta analisar os argumentos do aplicativo manualmente:

@SpringBootApplication
public class Application implements ApplicationRunner {

  public static void main(String[] args) {
    ApplicationArguments arguments = new DefaultApplicationArguments(args);
    // do whatever you like with your arguments
    // see above ...
    SpringApplication.run(Application.class, args);
  }

}

E, finalmente, se você precisar acessar seus argumentos em um bean, basta injetar o ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

Isso é incrível :).
John Humphreys - w00te 15/04

3

Argparse4j é o melhor que eu encontrei. Ele imita a biblioteca argparse do Python, que é muito conveniente e poderosa.


2

Se você quiser algo leve (tamanho do frasco ~ 20 kb) e simples de usar, tente o analisador de argumentos . Ele pode ser usado na maioria dos casos de uso, suporta a especificação de matrizes no argumento e não depende de nenhuma outra biblioteca. Funciona para Java 1.5 ou superior. O trecho abaixo mostra um exemplo de como usá-lo:

public static void main(String[] args) {
    String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
    ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
    InputData inputData = (InputData) argParser.parse(args);
    showData(inputData);

    new StatsGenerator().generateStats(inputData);
}

Mais exemplos podem ser encontrados aqui


1
Link está morto. Você matou seu projeto? :-(
beldaz 19/17

2

Eu não recomendaria o uso da Apache Common CLIbiblioteca, pois não é segura para threads.

Ele usa classes stateful com variáveis ​​estáticas e métodos para realizar trabalhos internos (por exemplo OptionBuilder) e deve ser usado apenas em situações fortemente controladas de thread único.


18
É bom lembrar que a biblioteca CLI não é segura para threads. No entanto, eu assumiria que a análise de linha de comando geralmente é feita em um único thread durante a inicialização do aplicativo e, dependendo dos parâmetros, outros threads podem ser iniciados.
Alexey Ivanov

0

Como um dos comentários mencionados anteriormente ( https://github.com/pcj/google-options ) seria uma boa opção para começar.

Uma coisa que eu quero adicionar é:

1) Se você encontrar algum erro de reflexão do analisador, tente usar uma versão mais recente da goiaba. No meu caso:

maven_jar(
    name = "com_google_guava_guava",
    artifact = "com.google.guava:guava:19.0",
    server = "maven2_server",
)

maven_jar(
    name = "com_github_pcj_google_options",
    artifact = "com.github.pcj:google-options:jar:1.0.0",
    server = "maven2_server",
)

maven_server(
    name = "maven2_server",
    url = "http://central.maven.org/maven2/",
)

2) Ao executar a linha de comando:

bazel run path/to/your:project -- --var1 something --var2 something -v something

3) Quando precisar da ajuda de uso, digite:

bazel run path/to/your:project -- --help

-1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.