Comment analyser les arguments de ligne de commande en Java?


586

Quelle est la bonne façon d'analyser les arguments de ligne de commande en Java?


4
Voir args4j et un exemple détaillé de son utilisation: martin-thoma.com/how-to-parse-command-line-arguments-in-java
Martin Thoma

On dirait que je suis assez tard pour cette fête, mais j'ai écrit un gestionnaire d'arguments en ligne de commande pour Java et je l'ai mis sur GitHub: MainArgsHandler . En ce qui concerne le thread fermé, je pense que c'est un thread très utile, mais il devrait éventuellement être migré vers le site Stack Exchange Programmers pour une discussion générale sur la programmation.
Bobulous

@RedGlyph - Il semble que SO / SE doive simplifier ses règles. La question aurait dû être: How to parse java command line arguments?. Mais personne ne veut vraiment écrire du code pour cela, mais plutôt utiliser un outil. Mais la recherche d'outils et autres n'est pas constructive :(
AlikElzin-kilaka

6
A voté pour sa réouverture. @AlikElzin: En effet, ils ont besoin de revoir leur processus de modération. Je soupçonne qu'il y a un badge pour fermer tant de questions, et que cela incite les futurs modérateurs à être trop zélés.
RedGlyph

8
Cette question est un pot de miel pour les mauvaises réponses / une ligne et les recommandations d'outils. Il devrait rester fermé.
JAL

Réponses:


405

Découvrez-les:

Ou lancez le vôtre:


Par exemple, voici comment vous utilisez commons-clipour analyser 2 arguments de chaîne:

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);

    }

}

utilisation depuis la ligne de commande:

$> 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
Notez que contrairement à de nombreuses autres bibliothèques Apache, Apache CLI n'a pas de dépendances.
Vladimir Dyuzhev

9
Le seul inconvénient de nombreux projets d'apache-commons est qu'ils obtiennent de moins en moins de commits et finissent par devenir obsolètes.
Brett Ryan

4
Voici la page "Scénarios d'utilisation" pour le projet CLI Apache, détaillant comment commencer rapidement à l'utiliser: commons.apache.org/cli/usage.html
Brad Parks

Je ne suppose pas qu'il y en ait un exactement comme Args4J / JCommander sauf où vous définissez une interface et annotez les méthodes? Je n'ai jamais pu m'intéresser aux cours qui "initialisent effrayants" les champs privés ...
Trejkaz

5
@RemkoPopma votre bibliothèque picocli a fière allure et merci de l'avoir fait, vraiment. Mais je considère ce que vous faites ici et dans d'autres articles (éditez les réponses acceptées et faites la promotion de votre bibliothèque en haut sans même révéler que c'est une édition qui ne vient pas de l'auteur original de l'article et c'est votre bibliothèque) un horrible abus horrible de vos pouvoirs de modération. Signaler cela à d'autres mods.
Alexander Malakhov le

312

Jetez un œil au JCommander le plus récent .

Je l'ai créé. Je suis heureux de recevoir des questions ou des demandes de fonctionnalités.


7
Heureux que vous aimiez JCommander :-) Je ne voulais pas ajouter trop de sémantique à la façon dont les indicateurs sont traités, il vous suffit donc d'ajouter des synonymes dans les annotations que vous utilisez: @Parameter (names = {"-h", "- -help "}) Je pensais que c'était un compromis raisonnable.
Cedric Beust

14
Excellent outil. Puissant, flexible et vous n'avez pas à gérer les analyseurs d'option traditionnels ennuyeux.
IanGilham

3
Oui, je pense que j'aurais écrit mon propre analyseur d'arguments en ligne de commande exactement de la même manière que vous avez écrit JCommander. Bon travail.
SRG

9
@CedricBeust, c'est une brillante bibliothèque, je vous remercie beaucoup. Comme nous pouvons définir nos propres classes Args qui peuvent ensuite être transmises sans aucune dépendance à une classe de bibliothèques, cela le rend extrêmement flexible.
Brett Ryan

2
souffle la compétition hors de l'eau!
Marcus Junius Brutus

235

7
@Ben Flynn hehe, il y a des roues en forme assez surprenantes et intéressantes. Je suppose que c'est une façon presque inoffensive de montrer qu'il y a bien plus d'une façon de le faire!
lexicalscope

14
Je note que l'auteur de JOpt Simple maintient une liste très similaire! Ce dont nous avons besoin, c'est de transformer ces listes en un tableau, répertoriant les fonctionnalités et les points d'intérêt, afin que nous, les pauvres utilisateurs, puissions faire un choix éclairé.
Tom Anderson

1
J'ai construit Rop - github.com/ryenus/rop , qui propose une solution basée sur des annotations que vous déclarez des commandes et des options via des classes et des champs simples, à peu près une façon déclarative de construire des analyseurs de ligne de commande. il peut créer des applications comme Git (single-cmd) ou Maven (multi-cmd).
ryenus

8
La plupart des projets répertoriés sont essentiellement des abandons de logiciels. Après avoir parcouru la liste, je dirais que les gros frappeurs, qui sont activement maintenus et populaires, semblent être communs-cli, jcommander, args4j, jopt-simple et picocli. Toutes mes excuses aux auteurs de choses comme argparse4j et cli-parser - J'ai dû faire un classement quelque peu arbitraire, et j'ai choisi un top cinq, clairement d'autres projets de la liste sont populaires et toujours en développement actif.
George Hawkins, le

2
Je mets au défi quelqu'un d'inclure la date de la dernière version stable de chaque analyseur.
Sledge

50

Il est 2020, il est temps de faire mieux que Commons CLI ... :-)

Devriez-vous créer votre propre analyseur de ligne de commande Java ou utiliser une bibliothèque?

De nombreuses petites applications de type utilitaire exécutent probablement leur propre analyse en ligne de commande pour éviter la dépendance externe supplémentaire. picocli peut être une alternative intéressante.

Picocli est une bibliothèque et un cadre modernes permettant de créer facilement des applications de ligne de commande GraalVM puissantes et conviviales. Il vit dans 1 fichier source afin que les applications puissent l'inclure comme source pour éviter d'ajouter une dépendance.

Il prend en charge les couleurs, la saisie semi-automatique, les sous-commandes, etc. Écrit en Java, utilisable depuis Groovy, Kotlin, Scala, etc.

Aide à l'utilisation minimale avec les couleurs ANSI

Fonctionnalités:

  • Basé sur les annotations: déclaratif , évite la duplication et exprime l' intention du programmeur
  • Pratique: analysez les entrées utilisateur et exécutez votre logique métier avec une seule ligne de code
  • Tout fortement saisi - options de ligne de commande ainsi que paramètres de position
  • Options courtes en cluster POSIX ( <command> -xvfInputFileainsi que <command> -x -v -f InputFile)
  • Contrôle à grain fin : un modèle d'arité qui permet un nombre minimum, maximum et variable de paramètres, par exemple "1..*","3..5"
  • Sous-commandes (peuvent être imbriquées à une profondeur arbitraire)
  • Riche en fonctionnalités : groupes d'arguments composables, division d'arguments entre guillemets, sous-commandes répétables et bien d'autres
  • Convivial : le message d'aide à l'utilisation utilise des couleurs pour contraster des éléments importants tels que les noms d'options du reste de l'aide à l'utilisation pour réduire la charge cognitive de l'utilisateur
  • Distribuez votre application en tant qu'image native GraalVM
  • Fonctionne avec Java 5 et supérieur
  • Documentation complète et minutieuse

Le message d'aide à l'utilisation est facile à personnaliser avec des annotations (sans programmation). Par exemple:

Message d'aide sur l'utilisation étendue( source )

Je n'ai pas pu résister à l'ajout d'une capture d'écran supplémentaire pour montrer quels messages d'aide à l'utilisation sont possibles. L'aide à l'utilisation est le visage de votre application, alors soyez créatif et amusez-vous!

démo picocli

Avertissement: j'ai créé picocli. Commentaires ou questions très bienvenus.


5
Du pur génie! C'est dommage que cette réponse soit enterrée au fond. Apache Commons CLI est verbeux, bogué et n'a pas été mis à jour depuis longtemps. Et je ne veux pas utiliser l'analyseur CLI de Google, car je ne veux pas de publicités ciblées basées sur l'historique d'utilisation de mon argument de ligne de commande. Mais ça a l'air un peu plus bavard que picocli de toute façon.
Pete

2
J'appuie @Pete ici ... J'ai parcouru la liste ci-dessus, ce qui était une perte de temps complète avec cette enterrée au fond. Cela devrait être la meilleure réponse d'un mile. Bon travail! Mes exigences ne pouvaient pas être couvertes par apache CLI ou la plupart de ces autres analyseurs. Ils étaient difficiles même pour picocli mais cela m'a donné la chose la plus proche de la syntaxe / du comportement que je voulais et était suffisamment flexible pour pirater ce dont j'avais vraiment besoin. En prime, il est superbe grâce aux éléments ANSI.
Shai Almog

@ShaiAlmog La réponse la plus votée est vieille de 10 ans et obsolète. Je reconnais que recommander CLI de Commons en 2019 est trompeur à mon humble avis. Veuillez envisager de réécrire la première réponse pour la mettre à jour.
Remko Popma

Je vois que vous avez déjà essayé cela, je ne pense pas que cela fonctionnera pour moi non plus ... Si vous aviez choisi un nom comme 1Picoli, nous aurions pu trier la 3ème réponse par ordre alphabétique ;-)
Shai Almog

Je pense que la raison pour laquelle mon changement a été annulé est que je n'ai pas divulgué mon affiliation (que je suis l'auteur). D'autres personnes ne devraient pas avoir ce problème.
Remko Popma

23

J'ai utilisé JOpt et l'ai trouvé assez pratique: http://jopt-simple.sourceforge.net/

La première page fournit également une liste d'environ 8 bibliothèques alternatives, vérifiez-les et choisissez celle qui convient le mieux à vos besoins.


21

Quelqu'un m'a signalé dernièrement args4j qui est basé sur des annotations. J'aime vraiment ça!


1
+1 pour Args4J! Extrêmement convivial, flexible et compréhensible. Je pense que ce devrait être la bibliothèque standard pour créer des applications CLI Java.
Zearin

Génial qu'il puisse gérer l'impression d'utilisation non ordonnée (triée par ordre de champ), ce que JCommander ne peut pas, et il est plus flexible.
Daniel Hári

@ DanielHári Juste pour information, cette fonctionnalité a été ajoutée dans JCommander (fin février 2017).
Nathan

9

Il s'agit de la bibliothèque d'analyse de ligne de commande de Google open source dans le cadre du projet Bazel. Personnellement, je pense que c'est le meilleur, et beaucoup plus facile que Apache CLI.

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

Installation

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>

Usage

Créez une classe qui étend OptionsBaseet définit votre @Option( vos ).

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;

}

Analysez les arguments et utilisez-les.

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


Salut Paul. Quand je lis votre réponse ou la documentation de votre projet, je n'ai aucune idée du type de ligne de commande qu'il peut gérer. Par exemple, vous pouvez fournir quelque chose comme myexecutable -c file.json -d 42 --outdir ./out. Et je ne vois pas comment vous définissez les options de description courte / longue / Acclamations
olibre



7

Je sais que la plupart des gens ici vont trouver 10 millions de raisons pour lesquelles ils n'aiment pas mon chemin, mais peu importe. J'aime garder les choses simples, donc je sépare juste la clé de la valeur en utilisant un '=' et je les stocke dans un HashMap comme ceci:

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

Vous pouvez toujours maintenir une liste avec les arguments que vous attendez, pour aider l'utilisateur au cas où il aurait oublié un argument ou en aurait utilisé un mauvais ... Cependant, si vous voulez trop de fonctionnalités, cette solution n'est pas pour vous de toute façon.


7

Peut-être que ces






4

Si vous utilisez déjà Spring Boot, l'analyse des arguments sort de la boîte.

Si vous souhaitez exécuter quelque chose après le démarrage, implémentez l' 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
  }
}

Votre runméthode sera invoquée après le démarrage réussi du contexte.

Si vous avez besoin d'accéder aux arguments avant de lancer votre contexte d'application, vous pouvez simplement analyser manuellement les arguments d'application:

@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);
  }

}

Et enfin, si vous avez besoin d'accéder à vos arguments dans un bean, injectez simplement ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

C'est génial :).
John Humphreys - w00te

3

Argparse4j est le meilleur que j'ai trouvé. Il imite la bibliothèque d'argparse de Python qui est très pratique et puissante.


2

Si vous voulez quelque chose de léger (taille du pot ~ 20 ko) et simple à utiliser, vous pouvez essayer l' analyseur d'arguments . Il peut être utilisé dans la plupart des cas d'utilisation, prend en charge la spécification de tableaux dans l'argument et ne dépend d'aucune autre bibliothèque. Cela fonctionne pour Java 1.5 ou supérieur. L'extrait ci-dessous montre un exemple sur la façon de l'utiliser:

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);
}

Plus d'exemples peuvent être trouvés ici


1
Le lien est mort. Avez-vous tué votre projet? :-(
beldaz

2

Je ne recommanderais pas d'utiliser la Apache Common CLIbibliothèque, car elle n'est pas sûre pour les threads.

Il utilise des classes avec état avec des variables statiques et des méthodes pour effectuer un travail interne (par exemple OptionBuilder) et ne doit être utilisé que dans des situations à contrôle unique à thread unique.


18
Il est bon de garder à l'esprit que la bibliothèque CLI n'est pas adaptée aux threads. Cependant, je suppose que l'analyse de la ligne de commande est généralement effectuée dans un seul thread au démarrage de l'application, puis, en fonction des paramètres, d'autres threads peuvent être démarrés.
Alexey Ivanov

0

Comme l'un des commentaires mentionnés précédemment ( https://github.com/pcj/google-options ) serait un bon choix pour commencer.

Une chose que je veux ajouter est:

1) Si vous rencontrez une erreur de réflexion de l'analyseur, essayez d'utiliser une version plus récente de la goyave. dans mon cas:

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) Lors de l'exécution de la ligne de commande:

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

3) Lorsque vous avez besoin de l'aide à l'utilisation, tapez simplement:

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

-1

Pour les utilisateurs de Spring, nous devons également mentionner https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html et son frère jumeau https: //docs.spring .io / spring / docs / current / javadoc-api / org / springframework / core / env / JOptCommandLinePropertySource.html (implémentation JOpt de la même fonctionnalité). L'avantage de Spring est que vous pouvez lier directement les arguments de la ligne de commande aux attributs, il y a un exemple ici https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/ CommandLinePropertySource.html

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.