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.