Befehlszeilenoptionsparser für Java

Ich schreibe eine Shell in Java, weil ich schon viel zu lange nicht mehr in Java programmiert und vieles davon vergessen habe. Ich wollte meinen eigenen schreiben, aber im Moment hätte ich gerne einen funktionierenden Prototyp, also würde ich gerne einen vorhandenen Befehlszeilen-Optionsparser einfügen.

Anforderungen:

  • Nimmt ein beliebiges Stringoder String[](dh verwendet nicht die Argumente von der Befehlszeile)
  • Akzeptiert Argumente in einem ähnlichen Format wie getopt(die erweiterte GNU-Version); speziell:
    • Mehrere Einzelbuchstaben-Optionen können verbunden werden (z. B. -a -b -cbis -abc)
    • Unterstützt lange Optionen (z. B. --message="Hello!") (obwohl es keine langen Optionen mit einem Bindestrich unterstützen muss)
    • Geht davon aus, dass alle nicht-optionsähnlichen Bits am Ende Parameter sind, die normal übergeben werden müssen (z. B. -abc --long="Hello!" param1 param2sagt mir, dass die Parameter param1und sind param2) .
    • --kann verwendet werden, um Optionen von Argumenten zu trennen (z. B. -ab --custom="hello" -- -file_starting_with_hyphen -anothergibt mir die Optionen/Flags a, b, und custommit den entsprechenden Werten und sagt mir, dass die Argumente -file_starting_with_hyphenund sind -another)
    • Leerzeichen können Teil von Argumenten sein, wenn sie in Anführungszeichen stehen.
    • Ein Optionsname, gefolgt von einem Wert, wird als die Option mit diesem Wert geparst (z. B. -h foosagt, dass es eine Option gibt, h, mit einem Wert, foo)
  • Völlig plattformübergreifend
  • Ich muss nicht angeben, nach welchen Optionen ich suche (dh ich übergebe ihm ein Stringoder String[]und es sagt mir, welche Flags/Optionen gesetzt wurden, im Gegensatz zu der Suche nach den Optionen, die ich setzen möchte, und der Annahme, dass der Rest Argumente sind )
    • Das bedeutet, dass keine Anmerkungen verwendet werden, um anzugeben, wo die Flag-Werte gespeichert werden sollen . Mindestens zwei Antworten haben dies bisher getan.
  • Kostenlos (wie in Bier)
  • Kann in jedem Projekt legal verwendet werden (dh nicht nicht kommerziell, nicht GPL)

Ideal, aber nicht notwendig:

  • Klein – eine Datei
  • Minimale Urheberrechtslizenz ( Kein Copyleft - ich mag es, mir keine Gedanken über rechtliche Probleme zu machen, und ich hasse Leute, die mir sagen wollen, dass ich meine Arbeit nicht verwenden kann, aber ich verdammt noch mal, bitte)
  • Verwendet die integrierten Schnittstellen ( java.util.Mapspeziell ), um Daten zurückzugeben. (So ​​kann ich später leichter meine eigene Funktion schreiben)
  • Open Source
@a_horse Wenn ich mich richtig erinnere, habe ich das nicht verwendet, weil ich angeben muss, nach welchen Optionen ich suche. Siehe die Anforderungen in der Frage.
Ich bin mir ziemlich sicher, dass Sie bei getopt auch die Argumente angeben müssen, nach denen Sie suchen. Und es erlaubt definitiv das Zusammenfügen von Einzelzeichen-Argumenten. Wie unterscheidet man also zwischen "-top" als langem Argument und der Kombination von -t, -o und -p, ohne anzugeben, was zulässig ist? Ich erwähne dies, weil " works like getopt" Ihre zweite Anforderung ist.
@CPerkins "like" bedeutet hier "ähnlich", nicht "genauso wie".
Okay danke. Neue Frage: Mir scheint, dass die Kombination der "nicht-optionsähnlichen Bits am Ende sind Parameter" und "Leerzeichen sind in Argumenten zulässig" mehrdeutig ist. Was ist, wenn die Argumente mit „-n=alpha beta“ enden? Ist "Beta" Teil des Wertes von n? Oder ist es ein Parameter?
@CPerkins Ich meinte, dass so etwas wie -n "foo bar baz"das Flag nmit parameter verarbeitet würde foo bar baz, anstatt nmit parameter "foound zwei Argumenten barund baz".
(Es ist eine Weile her, seit ich CLI-Sachen berührt habe, also bekomme ich möglicherweise "Parameter" und "Argument" rückwärts. Was ich meine, sollte klar sein.)
Aber was ist mit -n foo bar baz? Mit den Anführungszeichen ist klar, was Sie wollen. Ich denke, ich frage, ob Leerzeichen immer ein Trennzeichen sind.
@CPerkins Da. Abgesehen davon, eine vollständige technische Spezifikation zu schreiben, ist das so viel Spezifität, wie ich bereit bin, darauf einzugehen. Sie können den Rest daraus ableiten, wie Befehlszeilenoptionen normalerweise funktionieren
Ich habs. Siehe Antwort.

Antworten (4)

Sie könnten sich FeSimpleArgs ansehen

Ich glaube, es erfüllt alle Ihre Anforderungen:

Konzept: Ein sehr leichter Kommandozeilen-Parser. Akzeptiert Argumente entweder in der Form String oder String[], gibt eine Klasseninstanz zurück, die die Argumente in einer Zuordnung und die Parameter in einer Liste enthält.

Anforderungen:

  • Nimmt einen beliebigen String oder String[] (dh verwendet nicht die Argumente von der Kommandozeile) Ja
  • Nimmt Argumente in einem ähnlichen Format wie getopt (die erweiterte GNU-Version); speziell:
  • Mehrere Einzelbuchstaben-Optionen können verbunden werden (z. B. -a -b -c bis -abc) Ja
  • Unterstützt lange Optionen (z. B. --message="Hello!") (obwohl es keine langen Optionen mit einem Bindestrich unterstützen muss) Ja
  • Geht davon aus, dass alle nicht-optionsähnlichen Bits am Ende Parameter sind, die normal übergeben werden müssen (z. B. -abc --long="Hello!" param1 param2 sagt mir, dass die Parameter param1 und param2 sind) Ja
  • -- kann verwendet werden, um Optionen von Argumenten zu trennen (z. B. -ab --custom="hello" -- -file_starting_with_hyphen -another gibt mir die Optionen/Flags a, b und custom mit den entsprechenden Werten und teilt mir mit, dass die Argumente sind -file_starting_with_hyphen und -another) Ja
  • Leerzeichen können Teil von Argumenten sein, wenn sie in Anführungszeichen stehen. Ja
  • Ein Optionsname gefolgt von einem Wert wird als die Option mit diesem Wert geparst (z. B. -h foo sagt, dass es eine Option h mit einem Wert foo gibt). Ja

  • Vollständig plattformübergreifend Ja

  • Ich muss nicht angeben, nach welchen Optionen ich suche (dh ich übergebe einen String oder String[] und er sagt mir, welche Flags/Optionen gesetzt wurden, anstatt nach den Optionen zu suchen, die ich setzen möchte, und davon auszugehen der Rest sind Argumente) Ja

zur nutzung:

  • Kostenlos (wie in Bier) Ja - Apache 2.0
  • Kann in jedem Projekt legal verwendet werden (dh nicht nicht kommerziell, nicht GPL) Ja - Apache 2.0
  • Minimale Urheberrechtslizenz (Keine Copyleft – ich mag es, mir keine Gedanken über rechtliche Probleme zu machen, und ich hasse Leute, die mir sagen wollen, dass ich meine Arbeit nicht verwenden darf, aber ich bitte verdammt noch mal, bitte) Ja – Apache 2.0

Veröffentlicht unter der Apache 2.0-Lizenz.

Ideal, aber nicht notwendig:

  • Klein – eine Datei Ja (eine Datei für den Parser, eine für die Komponententests, wird nicht zum Parsen benötigt)
  • Verwendet die integrierten Schnittstellen (insbesondere java.util.Map), um Daten zurückzugeben. (So ​​kann ich später leichter meine eigene Funktion schreiben) **Art von ** (Gibt eine Klasse zurück, die eine java.util.Map von Argumenten und eine Liste von Parametern enthält)

VERWENDUNG Verwendung: 1) Erstellen Sie eine Instanz von FeSimpleArgs

FeSimpleArgs parser = new FeSimpleArgs();

2) Verwenden Sie es, um Ihre Argumente zu analysieren:

FeSimpleArgs.Result result = parser.parse ("-def=value1 --GHI=value2 -a -b -c=value3 -n=\"foo bar baz\" -- param1 -param2"); 

3) Untersuchen Sie Ihre Ergebnisse: Aus dem Obigen besteht das Ergebnis aus einer Map, die die folgenden Argumente und Flags enthält (beachten Sie, dass „Argument“ oder „Flag“ keine wirkliche Bedeutung haben, ich verwende diese Begriffe nur, um zu trennen, ob sie gelten Werte oder nicht - alle befinden sich in derselben Map).

  • a
  • b
  • d
  • e
  • f mit Wert=Wert1
  • WHI mit Wert=Wert2
  • c mit Wert=Wert3
  • n mit value=foo bar baz (Anführungszeichen werden entfernt)

Und eine Liste mit diesen Parametern (beachten Sie, dass der führende Bindestrich erhalten bleibt) - param1 - -param2

4) Gewinn?

Weitere Beispiele finden Sie in den enthaltenen Unit-Tests.

Haftungsausschluss: Ich bin der Autor von FeSimpleArgs

Das scheint perfekt, danke! Eines jedoch; Wenn ich nur durch den Code blättere, sehe ich ein paar Dinge, die ausgeschaltet sind – wiederholt – compileein Pattern, das sich nie ändert, tokenize2nie verwendet wird und so weiter. Vielleicht möchten Sie eine Frage auf CodeReview.SE stellen .
Gute Beobachtungen. Tokenize2 sollte ein Versuch sein, eine andere Regex zu verwenden. Der eine macht jetzt nicht das, was ich wirklich möchte, nämlich die gesamte Zeichenfolge in Anführungszeichen zu ziehen, selbst wenn etwas davor steht. Und ich mag es nicht, die Anführungszeichen zu entfernen. Es ist wohl immer noch ein Work in Progress, aber selbst in seinem unvollkommenen Zustand besteht es alle Tests.

Ich habe args4j erfolgreich in einer Reihe von Projekten eingesetzt. Es wurde von Kohsuke Kawaguchi entwickelt, der auch Jenkins entwickelt hat, Hauptentwickler für JAXB und andere Projekte war, also hat er einen sehr guten Stammbaum.

Ich glaube, ich habe es in der Frage schlecht formuliert, aber ich suche nach etwas, an das ich a übergeben String[]und (zum Beispiel) a Mapvon Optionen zurückbekommen kann, nicht etwas, das automatisch die Optionen aus den übergebenen Argumenten analysiert und der JAR-Datei zuweist . Außerdem muss es mir sagen können, welche Optionen mit welchen Argumenten übergeben wurden, anstatt dass ich ihm sage, nach welchen Optionen es suchen soll.

Hinweis: Diese Antwort ist veraltet, da OP die Frage bearbeitet hat, um eine Anforderung hinzuzufügen, die diese nicht erfüllt (es ist jedoch immer noch verdammt gut zu wissen). Siehe die Kommentare unten. Das OP möchte NICHT , dass Sie diese Antwort ablehnen.

Der Klassiker dafür in Unix/Linux, noch aus C-Tagen, war GetOpt().

Gnome hat hier einen Java-Port .

Ich suchte nach etwas weniger Zustandsbasiertem (ich denke, das ist das Wort? Dh eine Funktion, die eine Karte zurückgibt, anstatt sie zu durchsuchen). Außerdem muss eine Anforderung, die ich vergessen habe, in der Lage sein, beliebige Optionen aus der Zeichenfolge abzurufen, nicht nur die von mir angegebenen, da dies Argumente für jeden Befehl übergeben und die Argumente für parsen wird jeder würde viel zu viel Zeit in Anspruch nehmen. Trotzdem gefällt es mir, schon allein deshalb, weil ich ihren Code durchsuchen kann, um zu sehen, wie sie es gemacht haben.
Sie sollten Ihre Frage am besten für diese Anforderung aktualisieren, die Sie vergessen haben, damit die Leute Ihnen helfen können. fröhliches Schnuppern! Ich hoffe das hat ein wenig geholfen :-)
Ich habe es gerade getan :D und wie gesagt, es hat geholfen. Vielen Dank!
Und jetzt, da meine Antwort nicht mehr zutrifft, werde ich von Leuten herabgestimmt, die nicht darauf aus sind, das Ganze zu lesen. So ist das Leben :-(
Oh Mist. Das tut mir leid. Es könnte sich lohnen, dies zu bearbeiten, da dies geschrieben wurde, bevor einige der Anforderungen hinzugefügt wurden.
Mach dir keine Sorgen. Ich bin nicht wegen der Punkte hier :-) Wenn dir Stefans Antwort gefallen hat, akzeptiere sie bitte. Es ist auch vollkommen akzeptabel, Ihre eigene Antwort zu posten und sie zu akzeptieren. Der Punkt ist, zukünftigen Suchenden nach der gleichen Sache zu helfen
Das Problem mit Stefans ist, dass ich etwas haben möchte, das ich einfach einfügen kann, während Apaches CLI vierzehn Klassen und ein halbes Dutzend Codezeilen benötigt, nur um etwas zu analysieren, das leicht mit einer einzigen Methode erledigt werden könnte, die ein Stringund eine Aufzählung benötigt , oder ein Predicate<T>, oder so.
Bitte stellen Sie sicher, dass Sie Ihre Antwort hier posten, um anderen zu helfen. Wenn Sie etwas codieren, denken Sie bitte daran, es zu FOSSen und auf GitHub zu posten.
Ich habe keine Antwort, das ist das Problem. Ich habe jedoch nach einem gesucht, und das Schreiben meines eigenen war bisher nicht allzu schlecht
wir warten - mit angehaltenem Atem :-)

Picocli könnte von Interesse sein. Es handelt sich um eine einzelne Quelldatei, um Entwickler von Befehlszeilen-Apps zu ermutigen, sie als einfachere Alternative zum Schattieren von Gläsern in einem Uberjar als Quelle einzuschließen. Es erfüllt auch alle anderen Anforderungen, die im OP - UPDATE angegeben sind: mit Ausnahme der Anforderung, dass Optionen nicht zur Kompilierzeit behoben werden können :-(.

UPDATE 2: picocli 3.x bietet zusätzlich zur Annotations-API eine programmatische API, erfüllt also jetzt alle Anforderungen. Beachten Sie, dass Groovy CliBuilder seit Groovy 2.5 auf Picocli basiert. Das ist genau das, wonach das OP fragt: Optionen und Positionsparameter dynamisch zu einem Befehl hinzufügen.

Es hat kürzlich eine Autovervollständigungsfunktion hinzugefügt.

Eine weitere Funktion, die Ihnen gefallen könnte, ist die farbige Nutzungshilfe.

Minimale Verwendungshilfe mit ANSI-Farben

Parser-Funktionen:

  • Anmerkungs-API: Das Parsen ist eine Codezeile in Ihrer Anwendung
  • Programmatische API: Alles, was mit Anmerkungen möglich ist, kann programmgesteuert ausgeführt werden
  • Alles stark typisiert - Befehlszeilenoptionen sowie Positionsparameter
  • POSIX-Cluster-Short-Optionen ( <command> -xvfInputFilesowie <command> -x -v -f InputFile) und GNU-Long-Optionen
  • Ein Aritätsmodell, das eine minimale, maximale und variable Anzahl von Parametern zulässt, z "1..*"."3..5"
  • Unterbefehle (können beliebig tief verschachtelt werden)
  • Funktioniert mit Java 5 und höher

Die Hilfemeldung zur Verwendung kann einfach mit Anmerkungen angepasst werden (ohne Programmierung). Zum Beispiel:

Hilfemeldung zur erweiterten Verwendung( Quelle )

Ich konnte nicht widerstehen, einen weiteren Screenshot hinzuzufügen, um zu zeigen, welche Hilfemeldungen zur Verwendung möglich sind. Die Nutzungshilfe ist das Gesicht Ihrer Anwendung, also seien Sie kreativ und haben Sie Spaß!

PicoCli-Demo

Haftungsausschluss: Ich habe Picocli erstellt. Feedback oder Fragen sehr willkommen.

Ich bin mir nicht sicher, ob Sie meine Frage vollständig gelesen haben. Bitte stellen Sie sicher, dass Sie alle Anforderungen durchgelesen haben.
Vielen Dank für die Klärung der Frage. Das muss ich in meiner Begeisterung übersehen haben.
Keine Bange. Es scheint eine großartige Option für einen normalen Befehlszeilen-Parser zu sein, aber wenn ich das wollte, hätte ich wahrscheinlich keine Frage stellen müssen. Es gibt viele Möglichkeiten da draußen.
Verstanden. Danke für das positive Feedback. Ich habe meine Antwort aktualisiert, um hervorzuheben, dass es keine gute Übereinstimmung ist. Ich hoffe, es ist immer noch eine nützliche Antwort für andere Leser ...
Beachten Sie, dass picocli seit picocli 3.x zusätzlich zur Annotations-API eine programmatische API bietet. Dies erfüllt alle Anforderungen des OP. Ein bemerkenswertes Beispiel ist Groovy CliBuilder: Seit Groovy 2.5 wird CliBuilder mit der programmgesteuerten API picocli implementiert.