Come posso analizzare gli argomenti della riga di comando in Java?


586

Qual è un buon modo per analizzare gli argomenti della riga di comando in Java?


4
Vedi args4j e un esempio dettagliato su come usarlo: martin-thoma.com/how-to-parse-command-line-arguments-in-java
Martin Thoma

Sembra che sia abbastanza tardi per questa festa, ma ho scritto un gestore di argomenti da riga di comando per Java e l'ho messo su GitHub: MainArgsHandler . Per quanto riguarda la chiusura del thread, penso che questo sia un thread molto utile, ma dovrebbe eventualmente essere migrato sul sito dei programmatori di Exchange Exchange per una discussione di programmazione generale.
Bobulous,

@RedGlyph - Sembra che SO / SE debba semplificare le loro regole. La questione avrebbe dovuto essere: How to parse java command line arguments?. Ma nessuno vuole davvero scrivere codice per farlo, ma preferisce usare uno strumento. Ma la ricerca di strumenti e cose simili non è costruttiva :(
AlikElzin-kilaka

6
Votato per la riapertura. @AlikElzin: In effetti, hanno bisogno di rivedere il loro processo di moderazione. Ho il sospetto che ci sia un distintivo per chiudere così tante domande, e che attiri il desiderio di essere moderatori di essere troppo zelanti.
RedGlyph

8
Questa domanda è un honeypot per risposte errate / a una riga e consigli sugli strumenti. Dovrebbe rimanere chiuso.
JAL

Risposte:


405

Dai un'occhiata a questi:

O fai il tuo:


Ad esempio, è così che si usa commons-cliper analizzare 2 argomenti stringa:

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

    }

}

utilizzo dalla riga di 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
A differenza di molte altre librerie Apache, l'interfaccia della riga di comando di Apache non ha dipendenze.
Vladimir Dyuzhev,

9
L'unico aspetto negativo di molti progetti apache-commons è che ottengono sempre meno impegni e alla fine diventano obsoleti.
Brett Ryan,

4
Ecco la pagina "Scenari di utilizzo" per il progetto CLI di Apache, che spiega come iniziare rapidamente a usarlo: commons.apache.org/cli/usage.html
Brad Parks

Suppongo che non esista esattamente uno come Args4J / JCommander, tranne dove si definisce un'interfaccia e si annotano i metodi? Non sono mai stato in grado di affezionarmi a lezioni che "inizializzano spettrale" campi privati ​​...
Trejkaz,

5
@RemkoPopma la tua libreria picocli è semplicemente fantastica e grazie per averlo fatto, davvero. Ma considero quello che stai facendo qui e in altri post (modifica le risposte accettate e promuovi la tua libreria in cima ad essa senza nemmeno rivelare che è una modifica non dall'autore originale del post ed è la tua lib) un orribile abuso dei tuoi poteri di moderazione. Contrassegnando questo ad altre mod.
Alexander Malakhov

312

Dai un'occhiata al più recente JCommander .

L'ho creato io. Sono felice di ricevere domande o richieste di funzionalità.


7
Sono contento che ti piaccia JCommander :-) Non volevo aggiungere troppa semantica al modo in cui vengono trattati i flag, quindi devi solo aggiungere sinonimi nelle annotazioni che usi: @Parameter (names = {"-h", "- -help "}) Ho pensato che fosse un ragionevole compromesso.
Cedric Beust,

14
Ottimo strumento. Potente, flessibile e non devi occuparti dei fastidiosi, tradizionali parser di opzioni.
IanGilham,

3
Sì, penso che avrei scritto il mio parser per l'argomento della riga di comando nello stesso modo in cui hai scritto JCommander. Ottimo lavoro.
SRG

9
@CedricBeust, questa è una libreria geniale, ti ringrazio molto. Dal momento che possiamo definire le nostre classi Args che possono essere passate in giro senza alcuna dipendenza da una classe di librerie, la rende estremamente flessibile.
Brett Ryan,

2
fa esplodere la concorrenza dall'acqua!
Marcus Junius Brutus,

235

7
@Ben Flynn hehe, ci sono alcune ruote sagomate abbastanza sorprendenti e interessanti. Immagino sia un modo per lo più innocuo per dimostrare che ci sono molti più di un modo per farlo!
lexicalscope,

14
Prendo atto che l'autore di JOpt Simple mantiene un elenco molto simile! Ciò di cui abbiamo bisogno del testo è trasformare questi elenchi in una tabella, elencando funzionalità e punti di interesse, in modo che noi poveri utenti possiamo fare una scelta informata.
Tom Anderson,

1
Ho creato Rop - github.com/ryenus/rop , che presenta una soluzione basata su annotazioni che dichiara comandi e opzioni tramite classi e campi semplici, praticamente un modo dichiarativo per costruire parser da riga di comando. può creare app Git (single-cmd) o Maven (multi-cmd).
reno il

8
La maggior parte dei progetti elencati sono essenzialmenteandonware. Dopo aver esaminato l'elenco direi che i grandi hit, che sono attivamente mantenuti e popolari, sembrano commons-cli, jcommander, args4j, jopt-simple e picocli. Mi scuso con gli autori di cose come argparse4j e cli-parser: ho dovuto fare una classifica un po 'arbitraria e ho scelto i primi cinque, chiaramente altri progetti nella lista sono popolari e ancora in fase di sviluppo attivo.
George Hawkins,

2
Sfido qualcuno a includere la data dell'ultima versione stabile di ogni parser.
Slitta

50

È il 2020, è tempo di fare meglio di Commons CLI ... :-)

Dovresti creare il tuo parser della riga di comando Java o utilizzare una libreria?

Molte piccole applicazioni simili a utility probabilmente eseguono il proprio analisi della riga di comando per evitare la dipendenza esterna aggiuntiva. picocli può essere un'alternativa interessante.

Picocli è una libreria e un framework moderni per creare con facilità app da riga di comando potenti, intuitive e compatibili con GraalVM. Vive in 1 file di origine, quindi le app possono includerlo come fonte per evitare l'aggiunta di una dipendenza.

Supporta colori, completamento automatico, sottocomandi e altro. Scritto in Java, utilizzabile da Groovy, Kotlin, Scala, ecc.

Aiuto per un utilizzo minimo con i colori ANSI

Caratteristiche:

  • Basato su annotazioni: dichiarativo , evita la duplicazione ed esprime l' intento del programmatore
  • Conveniente: analizzare l'input dell'utente ed eseguire la logica aziendale con una riga di codice
  • Tutto fortemente tipizzato : opzioni della riga di comando e parametri posizionali
  • Opzioni brevi cluster POSIX ( <command> -xvfInputFilenonché <command> -x -v -f InputFile)
  • Controllo a grana fine : un modello arity che consente un numero minimo, massimo e variabile di parametri, ad es "1..*"."3..5"
  • Sottocomandi (può essere nidificato a profondità arbitraria)
  • Ricco di funzionalità : gruppi arg componibili, suddivisione di argomenti quotati, sottocomandi ripetibili e molti altri
  • Facile da usare : il messaggio di aiuto per l'uso usa i colori per contrastare elementi importanti come i nomi delle opzioni dal resto dell'aiuto per ridurre il carico cognitivo sull'utente
  • Distribuisci la tua app come immagine nativa di GraalVM
  • Funziona con Java 5 e versioni successive
  • Documentazione ampia e meticolosa

Il messaggio di aiuto per l'uso è facile da personalizzare con le annotazioni (senza programmazione). Per esempio:

Messaggio di aiuto per l'uso esteso( fonte )

Non ho resistito all'aggiunta di uno screenshot in più per mostrare quali messaggi di aiuto sull'utilizzo sono possibili. L'aiuto all'utilizzo è il volto della tua applicazione, quindi sii creativo e divertiti!

demo picocli

Disclaimer: ho creato picocli. Feedback o domande molto gradite.


5
Genio puro! È un peccato che questa risposta sia sepolta in fondo. La CLI di Apache Commons è dettagliata, buggy e non è stata aggiornata da molto tempo. E non voglio usare il parser CLI di Google perché non voglio pubblicità mirate basate sulla cronologia di utilizzo dell'argomento della riga di comando. Ma sembra comunque un po 'più dettagliato di Picocli.
Pete,

2
Ho seguito @Pete qui ... Ho esaminato l'elenco sopra che era una completa perdita di tempo con questo sepolto in fondo. Questa dovrebbe essere la risposta migliore di un miglio. Ottimo lavoro! Le mie esigenze non potevano essere coperte dall'interfaccia della riga di comando di apache o dalla maggior parte di questi altri parser. Sono stati impegnativi anche per Picocli ma è stato in grado di darmi la cosa più vicina alla sintassi / comportamento che volevo ed era abbastanza flessibile da hackerare ciò di cui avevo veramente bisogno. Come bonus è bello grazie alla roba ANSI.
Shai Almog,

@ShaiAlmog La risposta più votata è di 10 anni e obsoleta. Concordo sul fatto che raccomandare la CLI di Commons nel 2019 sia fuorviante per IMHO. Si prega di considerare di riscrivere la risposta migliore per renderla più aggiornata.
Remko Popma,

Vedo che l'hai già provato, non credo che funzionerà neanche per me ... Se avessi scelto un nome come 1Picoli avremmo potuto ordinare la terza risposta in ordine alfabetico ;-)
Shai Almog

Penso che il motivo per cui è stato ripristinato il mio cambiamento sia che non ho rivelato la mia affiliazione (che sono l'autore). Le altre persone non dovrebbero avere questo problema.
Remko Popma,

23

Ho usato JOpt e l'ho trovato abbastanza utile: http://jopt-simple.sourceforge.net/

La prima pagina fornisce anche un elenco di circa 8 librerie alternative, verificale e scegli quella più adatta alle tue esigenze.


21

Qualcuno mi ha indicato di recente args4j che si basa sulle annotazioni. Mi piace veramente!


1
+1 per Args4J! Estremamente amico dell'uomo, flessibile e comprensibile. Penso che dovrebbe essere la libreria standard per la creazione di app CLI Java.
Zearin,

Fantastico che sia in grado di gestire la stampa non ordinata (ordinata per ordine di campo), che JCommander non può, ed è più flessibile.
Daniel Hári,

@ DanielHári Solo per informazione, questa funzionalità è stata aggiunta in JCommander (qualche volta alla fine di febbraio 2017).
Nathan,

9

Questa è la libreria di analisi della riga di comando di Google open source come parte del progetto Bazel. Personalmente penso che sia il migliore in circolazione e molto più semplice dell'interfaccia della riga di comando di Apache.

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

Installazione

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'
}

Esperto di

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

uso

Crea una classe che estende OptionsBasee definisce i tuoi @Option.

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;

}

Analizza gli argomenti e usali.

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


Ciao Paul. Quando leggo la tua risposta o la documentazione del tuo progetto non ho idea del tipo di riga di comando che può gestire. Ad esempio, potresti fornire qualcosa di simile myexecutable -c file.json -d 42 --outdir ./out. E non vedo come definisci le opzioni di breve / lunga / descrizione ... Saluti
olibre,



7

So che molte persone qui troveranno 10 milioni di motivi per cui non amano la mia strada, ma non importa. Mi piace mantenere le cose semplici, quindi separo la chiave dal valore usando un '=' e le memorizzo in una HashMap in questo modo:

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

Puoi sempre mantenere un elenco con gli argomenti che ti aspetti, per aiutare l'utente nel caso in cui abbia dimenticato un argomento o ne abbia usato uno sbagliato ... Tuttavia, se vuoi troppe funzionalità questa soluzione non fa comunque per te.


7

Forse questi






4

Se stai già utilizzando Spring Boot, l'analisi degli argomenti viene fuori dalla scatola.

Se vuoi eseguire qualcosa dopo l'avvio, implementa l' ApplicationRunnerinterfaccia:

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

Il tuo run metodo verrà invocato dopo che il contesto è stato avviato correttamente.

Se è necessario accedere agli argomenti prima di avviare il contesto dell'applicazione, è possibile semplicemente analizzare manualmente gli argomenti dell'applicazione:

@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 infine, se hai bisogno di accedere ai tuoi argomenti in un bean, basta inserire ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

Questo è bellissimo :).
John Humphreys - w00te,

3

Argparse4j è il migliore che abbia trovato. Imita il libparse argary di Python che è molto conveniente e potente.


2

Se vuoi qualcosa di leggero (dimensioni del vaso ~ 20 kb) e semplice da usare, puoi provare l' argomento-parser . Può essere utilizzato nella maggior parte dei casi d'uso, supporta la specifica di array nell'argomento e non ha alcuna dipendenza da qualsiasi altra libreria. Funziona con Java 1.5 o versioni successive. Il seguente estratto mostra un esempio su come usarlo:

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

Altri esempi possono essere trovati qui


1
Il link è morto. Hai ucciso il tuo progetto? :-(
beldaz,

2

Non consiglierei di usare Apache Common CLI libreria, in quanto non è thread-safe.

Utilizza classi stateful con variabili e metodi statici per eseguire lavori interni (ad es. OptionBuilder) E dovrebbe essere usato solo in situazioni fortemente controllate a thread singolo.


18
È bene tenere presente che la libreria CLI non è thread-safe. Tuttavia, suppongo che l'analisi della riga di comando venga in genere eseguita in un singolo thread all'avvio dell'applicazione e quindi, a seconda dei parametri, è possibile avviare altri thread.
Alexey Ivanov,

0

Come uno dei commenti menzionati in precedenza ( https://github.com/pcj/google-options ) sarebbe una buona scelta per iniziare.

Una cosa che voglio aggiungere è:

1) Se si verifica un errore di riflessione del parser, provare a utilizzare una versione più recente di guava. nel mio 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) Quando si esegue la riga di comando:

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

3) Quando hai bisogno della guida per l'uso, digita:

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

-1
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.