Jak analizować argumenty wiersza poleceń w Javie?


586

Jaki jest dobry sposób analizowania argumentów wiersza poleceń w Javie?


4
Zobacz args4j i szczegółowy przykład, jak go używać: martin-thoma.com/how-to-parse-command-line-arguments-in-java
— Martin Thoma

Wygląda na to, że jestem spóźniony na tę imprezę, ale napisałem program obsługi argumentów wiersza poleceń dla Javy i umieściłem go w GitHub: MainArgsHandler . Jeśli chodzi o zamykanie wątku, myślę, że jest to bardzo pomocny wątek, ale prawdopodobnie należy go przenieść na stronę Stack Exchange Programmers w celu ogólnej dyskusji na temat programowania.
— Bobulous

@RedGlyph - Wygląda na to, że SO / SE muszą uprościć swoje zasady. Pytanie powinno być: How to parse java command line arguments?. Ale nikt tak naprawdę nie chce pisać kodu, aby to zrobić, ale raczej użyć narzędzia. Ale szukanie narzędzi i polubień nie jest konstruktywne :(
— AlikElzin-kilaka

6
Zagłosowano na ponowne otwarcie. @AlikElzin: Rzeczywiście, muszą przejrzeć proces moderacji. Podejrzewam, że jest znaczek do zamykania tylu pytań i że to zachęca niedoszłych moderatorów do nadgorliwości.
— RedGlyph,

8
To pytanie jest honeypotem dla złych / jednowierszowych odpowiedzi i rekomendacji narzędzi. Powinien pozostać zamknięty.
— JAL,

Odpowiedzi:


405

Sprawdź te:

Lub rzuć własnym:


Na przykład w ten sposób commons-clianalizujesz 2 argumenty łańcuchowe:

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

    }

}

użycie z wiersza poleceń:

$> 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
Należy pamiętać, że w przeciwieństwie do wielu innych bibliotek Apache, interfejs CLI Apache nie ma zależności.
— Vladimir Dyuzhev

9
Jedynym minusem wielu projektów apache-commons jest to, że otrzymują coraz mniej zatwierdzeń i ostatecznie stają się przestarzałe.
— Brett Ryan,

4
Oto strona „Scenariusze użytkowania” dla projektu CLI Apache, szczegółowo opisująca, jak szybko zacząć z niego korzystać: commons.apache.org/cli/usage.html
— Brad Parks

Nie sądzę, żeby istniał taki jak Args4J / JCommander, chyba że definiujesz interfejs i adnotujesz metody? Nigdy nie byłem w stanie polubić zajęć, które „upiornie inicjalizują” prywatne pola…
— Trejkaz

5
@RemkoPopma twoja biblioteka picocli wygląda świetnie i dziękuję za to, naprawdę. Ale uważam, że to, co robisz tutaj i w innych postach (edytuj zaakceptowane odpowiedzi i promuj swoją bibliotekę na jej szczycie, nawet nie ujawniając, że jest to edycja nie pochodząca od oryginalnego autora posta i jego lib), jest okropnym okropnym nadużyciem twoich uprawnień moderacyjnych. Oznaczanie tego innym modom.
— Alexander Malakhov,

312

Spójrz na najnowszego JCommandera .

Stworzyłem to. Z przyjemnością otrzymam pytania lub prośby o nowe funkcje.


7
Cieszę się, że lubisz JCommandera :-) Nie chciałem dodawać zbyt dużego znaczenia semantycznego do sposobu traktowania flag, więc wystarczy dodać synonimy w używanych adnotacjach: @Parameter (names = {"-h", "- -help "}) Myślałem, że to rozsądny kompromis.
— Cedric Beust

14
Świetne narzędzie. Mocny, elastyczny i nie musisz radzić sobie z irytującymi, tradycyjnymi parserami opcji.
— IanGilham

3
Tak, myślę, że napisałbym własny parser argumentów wiersza poleceń dokładnie w taki sam sposób, jak napisałeś JCommander. Świetna robota.
— SRG

9
@CedricBeust, jest to genialna biblioteka, bardzo dziękuję. Ponieważ możemy zdefiniować własne klasy Args, które mogą być następnie przekazywane bez żadnej zależności od klasy bibliotek, czyni to je niezwykle elastycznym.
— Brett Ryan,

2
zdmuchuje konkurencję z wody!
— Marcus Junius Brutus

235

7
@Ben Flynn hehe, są tam dość zaskakujące i ciekawe kształty kół. Sądzę, że jest to w większości nieszkodliwy sposób pokazania, że ​​istnieje wiele sposobów na zrobienie tego!
— leksykalny

14
Zwracam uwagę, że autor JOpt Simple utrzymuje bardzo podobną listę! Potrzebujemy tekstu, aby zamienić te listy w tabelę, zawierającą funkcje i interesujące miejsca, abyśmy, biedni użytkownicy, mogli dokonać świadomego wyboru.
— Tom Anderson

1
Zbudowałem Rop - github.com/ryenus/rop , który zawiera rozwiązanie oparte na adnotacjach, które deklarujesz komendy i opcje za pomocą zwykłych klas i pól, co jest w zasadzie deklaratywnym sposobem budowania parserów wiersza poleceń. może budować aplikacje Git (single-cmd) lub Maven (multi-cmd).
— ryenus

8
Większość wymienionych projektów to głównie programy porzucające. Po przejrzeniu listy powiedziałbym, że duże hitters, które są aktywnie utrzymywane i popularne, wydają się być commons-cli, jcommander, args4j, jopt-simple i picocli. Przepraszam autorów takich rzeczy, jak argparse4j i cli-parser - musiałem sporządzić nieco arbitralny ranking i wybrałem pierwszą piątkę, wyraźnie inne projekty z listy są popularne i wciąż są w fazie rozwoju.
— George Hawkins,

2
Wzywam kogoś do podania daty ostatniego stabilnego wydania każdego parsera.
— Sanka

50

Jest rok 2020, czas na lepsze niż Commons CLI ... :-)

Czy należy zbudować własny analizator składni wiersza poleceń Java, czy skorzystać z biblioteki?

Wiele małych aplikacji podobnych do narzędzi prawdopodobnie przetwarza własne parsowanie wiersza poleceń, aby uniknąć dodatkowej zależności zewnętrznej. picocli może być interesującą alternatywą.

Picocli to nowoczesna biblioteka i środowisko do łatwego tworzenia wydajnych, przyjaznych dla użytkownika aplikacji obsługujących GraalVM. Znajduje się w 1 pliku źródłowym, więc aplikacje mogą uwzględnić go jako źródło, aby uniknąć dodawania zależności.

Obsługuje kolory, autouzupełnianie, podkomendy i wiele innych. Napisane w Javie, do użytku z Groovy, Kotlin, Scala itp.

Minimalne użycie pomaga w kolorach ANSI

Funkcje:

  • Oparte na adnotacjach: deklaratywne , pozwala uniknąć powielania i wyraża zamiary programisty
  • Wygodne: przeanalizuj dane wejściowe użytkownika i uruchom logikę biznesową za pomocą jednego wiersza kodu
  • Mocno wpisane wszystko - opcje wiersza poleceń, a także parametry pozycyjne
  • Klastry krótkie opcje POSIX ( <command> -xvfInputFilea także <command> -x -v -f InputFile)
  • Drobnoziarnisty sterowania : model arity który pozwala minimum, maksimum i zmienną liczbę parametrów, na przykład "1..*","3..5"
  • Podkomendy (można zagnieżdżać na dowolnej głębokości)
  • Bogaty w funkcje : składane grupy argumentów, dzielenie cytowanych argumentów, powtarzalne komendy i wiele innych
  • Przyjazny dla użytkownika : komunikat pomocy użytkowania używa kolorów do kontrastowania ważnych elementów, takich jak nazwy opcji z pozostałej części użycia, pomagając zmniejszyć obciążenie poznawcze użytkownika
  • Rozpowszechnij swoją aplikację jako natywny obraz GraalVM
  • Działa z Javą 5 i nowszymi
  • Obszerna i drobiazgowa dokumentacja

Komunikat pomocy dotyczącej użytkowania można łatwo dostosować za pomocą adnotacji (bez programowania). Na przykład:

Komunikat pomocy dotyczącej rozszerzonego użytkowania( źródło )

Nie mogłem się powstrzymać przed dodaniem jeszcze jednego zrzutu ekranu, aby pokazać, jakie komunikaty pomocy dotyczące użytkowania są możliwe. Pomoc dotycząca użytkowania jest obliczem Twojej aplikacji, więc bądź kreatywny i baw się dobrze!

demo picocli

Uwaga: Stworzyłem picocli. Informacje zwrotne lub pytania bardzo mile widziane.


5
Czysty geniusz! Szkoda, że ​​odpowiedź jest zakopana na dole. Interfejs Apache Commons CLI jest pełny, zawiera błędy i nie był aktualizowany od dłuższego czasu. Nie chcę używać analizatora składni CLI Google, ponieważ nie chcę ukierunkowanych reklam opartych na historii użycia argumentów w wierszu poleceń. Ale i tak wygląda trochę bardziej verbose niż picocli.
— Pete

2
Drugie @Pete tutaj ... Przejrzałem powyższą listę, co było całkowitą stratą czasu z tym ukrytym na dole. To powinna być najlepsza odpowiedź o milę. Dobra robota! Moje wymagania nie mogą być pokryte przez interfejs Apache CLI lub większość tych innych parserów. Byli wyzwaniem nawet dla picocli, ale był w stanie dać mi najbliższą składnię / zachowanie, którego chciałem i był wystarczająco elastyczny, aby włamać się do tego, czego naprawdę potrzebowałem. Jako bonus wygląda świetnie dzięki ANSI.
— Shai Almog

@ShaiAlmog Najczęściej głosowana odpowiedź ma 10 lat i jest nieaktualna. Zgadzam się, że rekomendowanie Commons CLI w 2019 r. Wprowadza w błąd IMHO. Rozważ przepisanie najważniejszej odpowiedzi, aby była bardziej aktualna.
— Remko Popma,

Widzę, że już to próbowałeś, nie sądzę, aby to również działało dla mnie ... Gdybyś wybrał nazwę taką jak 1Picoli, moglibyśmy posortować trzecią odpowiedź alfabetycznie ;-)
— Shai Almog

Wydaje mi się, że powodem mojej zmiany było cofnięcie tego, że nie ujawniłem swojej przynależności (że jestem autorem). Inne osoby nie powinny mieć tego problemu.
— Remko Popma,

23

Użyłem JOpt i okazało się, że jest to całkiem przydatne: http://jopt-simple.sourceforge.net/

Na pierwszej stronie znajduje się również lista około 8 alternatywnych bibliotek, sprawdź je i wybierz tę, która najbardziej odpowiada Twoim potrzebom.


21

Ktoś wskazał mi ostatnio na args4j, który jest oparty na adnotacjach. Naprawdę to lubie!


1
+1 dla Args4J! Niezwykle przyjazny dla człowieka, elastyczny i zrozumiały. Myślę, że powinna to być standardowa biblioteka do tworzenia aplikacji Java CLI.
— Zearin,

Świetnie, że może obsłużyć nieuporządkowany (posortowany według kolejności pól) wydruk użytkowania, którego JCommander nie może, i jest bardziej elastyczny.
— Daniel Hári,

@ DanielHári Tylko dla informacji, ta funkcjonalność została dodana w JCommander (kiedyś pod koniec lutego 2017 r.).
— Nathan

9

Jest to biblioteka parsująca Google'a z linii poleceń, otwarta w ramach projektu Bazel. Osobiście uważam, że jest najlepszy i o wiele łatwiejszy niż CLI Apache.

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

Instalacja

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>

Stosowanie

Utwórz klasę, która rozszerza OptionsBasei definiuje twoje @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;

}

Analizuj argumenty i używaj ich.

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


Cześć Paweł. Kiedy czytam twoją odpowiedź lub dokumentację projektu, nie mam pojęcia, jaki rodzaj wiersza poleceń może obsłużyć. Na przykład możesz podać coś takiego myexecutable -c file.json -d 42 --outdir ./out. I nie rozumiem, jak definiujecie opcje krótkich / długich / opisów ... Pozdrawiam
— olibre



7

Wiem, że większość ludzi znajdzie 10 milionów powodów, dla których nie lubią mojej drogi, ale nieważne. Lubię upraszczać, więc po prostu oddzielam klucz od wartości za pomocą '=' i przechowuję je w HashMap jak poniżej:

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

Zawsze możesz utrzymywać listę z argumentami, których oczekujesz, aby pomóc użytkownikowi na wypadek, gdyby zapomniał o argumentie lub użył niewłaściwego ... Jednak jeśli chcesz mieć zbyt wiele funkcji, to rozwiązanie i tak nie jest dla Ciebie.


7

Może te






4

Jeśli korzystasz już z Spring Boot, parsowanie argumentów wychodzi z pudełka.

Jeśli chcesz uruchomić coś po uruchomieniu, zaimplementuj ApplicationRunnerinterfejs:

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

Twoja runmetoda zostanie wywołana po pomyślnym uruchomieniu kontekstu.

Jeśli potrzebujesz dostępu do argumentów przed uruchomieniem kontekstu aplikacji, możesz po prostu ręcznie przeanalizować argumenty aplikacji:

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

}

I na koniec, jeśli potrzebujesz dostępu do swoich argumentów w fasoli, po prostu wstrzyknij ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

To jest niesamowite :).
— John Humphreys - w00te

3

Argparse4j jest najlepszym, jaki znalazłem. Naśladuje on argusową bibliotekę Pythona, która jest bardzo wygodna i potężna.


2

Jeśli chcesz czegoś lekkiego (rozmiar słoika ~ 20 kb) i prostego w użyciu, możesz wypróbować argument-parser . Może być używany w większości przypadków użycia, obsługuje określanie tablic w argumencie i nie jest zależny od żadnej innej biblioteki. Działa z Javą 1.5 lub nowszą. Poniżej fragment pokazuje przykład, jak go używać:

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

Więcej przykładów można znaleźć tutaj


1
Link nie działa. Czy zabiłeś swój projekt? :-(
— beldaz

2

Nie polecam korzystania z Apache Common CLIbiblioteki, ponieważ nie jest ona bezpieczna dla wątków.

Wykorzystuje klasy stanowe ze zmiennymi statycznymi i metodami do wykonywania pracy wewnętrznej (np. OptionBuilder) I powinien być stosowany tylko w ściśle kontrolowanych sytuacjach jednowątkowych.


18
Warto pamiętać, że biblioteka CLI nie jest bezpieczna dla wątków. Zakładam jednak, że analiza wiersza poleceń jest zwykle wykonywana w jednym wątku podczas uruchamiania aplikacji, a następnie, w zależności od parametrów, można uruchomić inne wątki.
— Aleksiej Iwanow

0

Ponieważ jeden z wcześniej wspomnianych komentarzy ( https://github.com/pcj/google-options ) byłby dobrym wyborem na początek.

Chcę dodać jedną rzecz:

1) Jeśli wystąpi błąd odbicia parsera, spróbuj użyć nowszej wersji guawy. w moim przypadku:

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) Podczas uruchamiania wiersza polecenia:

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

3) Gdy potrzebujesz pomocy dotyczącej użytkowania, po prostu wpisz:

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

-1
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.