Während der Entwicklung der Anwendung fragte ich mich: Wie soll ich Befehlszeilenargumente entwerfen?
Viele Programme verwenden Formeln wie diese -argument value
oder /argument value
. Die Lösung, die mir in den Sinn kam, war argument:value
. Ich fand es gut, weil es ohne Leerzeichen keine Möglichkeit gibt, Werte und Argumente durcheinander zu bringen. Es ist auch einfach, eine Zeichenfolge beim ersten :
Zeichen von links in zwei Teile zu teilen .
Meine Fragen sind:
- Ist die beliebte
-argument value
Formel besser alsargument:value
(lesbarer, einfacher zu schreiben, fehlerfrei, für erfahrene Entwickler einfacher zu verstehen)? - Gibt es einige allgemein bekannte Regeln, denen ich beim Entwerfen von Befehlszeilenargumenten folgen sollte (außer wenn es funktioniert, ist es in Ordnung)?
Nach einigen Details gefragt, werde ich es zur Verfügung stellen. Ich denke jedoch, dass sie die Antworten nicht beeinflussen sollten. Die Frage ist über gute Gewohnheiten im Allgemeinen. Ich denke, sie sind für alle Arten von Anwendungen gleich.
Wir arbeiten an einer Anwendung, die an öffentlichen Orten (Touch Totems, Tabellen) verwendet werden soll. Anwendungen werden mit Qt Quick 5 (C ++, QML, JS) geschrieben. Auf Geräten ist Windows 8.1 / 10 installiert. Wir werden eine Front-End-Schnittstelle zur Verwaltung der Geräte bereitstellen. Einige erfahrene Administratoren möchten die Anwendung jedoch möglicherweise selbst konfigurieren. Es ist von der Seite des Geschäfts nicht sehr wichtig, aber da ich dem zustimme, was Kilian Foth sagte, möchte ich nicht, dass meine Anwendung für einen Benutzer schmerzhaft ist. Da ich im Internet nicht finde, was ich will, habe ich hier gefragt.
Für fortgeschrittene Stack Exchange-Benutzer: Ich wollte, dass diese Frage allgemein ist. Vielleicht qualifiziert es sich für das Community-Wiki (ich weiß nicht, ob vorhandene Fragen mit Antworten konvertiert werden können). Da ich möchte, dass diese Frage unabhängig von Betriebssystem und Programmiersprache ist, können die hier aufgeführten Antworten eine wertvolle Lektion für andere Entwickler sein.
quelle
ls -ltr
, um die Optionen zu kombinieren-l
,-t
und-r
. GNU-Programme erlauben normalerweise auch wortbasierte Optionen mit einem doppelten Bindestrich--reverse
anstelle von-r
. Es gibt andere gängige Konventionen-h
, um Hilfe--
-
-argument value
nicht-argument:value
üblich. Üblich sind-a value
,-avalue
und--argument=value
.getopt(s)
), wo Sie können.Antworten:
Auf POSIX-Systemen (z. B. Linux, MacOSX) würde ich, zumindest für Programme, die möglicherweise in einem Shell-Terminal gestartet wurden (z. B. den meisten von ihnen), die Verwendung der GNU-Kodierungskonventionen empfehlen (in denen auch gebräuchliche Argumentnamen aufgeführt sind) und in den Richtlinien für POSIX-Dienstprogramme nachsehen , auch für proprietäre Software:
immer behandeln
--version
und--help
(/bin/true
akzeptiert sie sogar !!). Ich verfluche die Autoren von Software nicht verstehend--help
, ich hasse sie (weilprog --help
es der erste Befehl ist, den ich auf einem neuen Programm versuche)! Oft--help
kann als abgekürzt werden-h
Lassen Sie die
--help
Nachricht alle Optionen auflisten (es sei denn, Sie haben zu viele davon ... in diesem Fall listen Sie die am häufigsten verwendeten auf und verweisen Sie explizit auf eineman
Seite oder eine URL) und Standardwerte von Optionen, und möglicherweise wichtig (und programmspezifisch) ) Umgebungsvariablen. Diese Optionslisten bei Optionsargumentfehler anzeigen.akzeptieren
-a
kurze Argument (Einzelbuchstaben) und einige Äquivalent haben--long-argument
, so-a2
--long-argument=2
,--long-argument 2
; Natürlich könnten Sie (für selten verwendete Optionen) einen--only-long-argument
Namen haben; für modale Argumente ohne zusätzliche Optionen-cf
wird in der Regel wie folgt vorgegangen:-c -f
usw. Ihr-argument:value
Vorschlag ist also komisch, und ich empfehle, dies nicht zu tun.benutze GLIBC getopt_long oder besser (zB argp_parse , in OCaml ist es ein
Arg
Modul , ...)verwenden oft
-
für Standard - Ein- oder Ausgang (wenn Sie nicht tun können, handhaben/dev/stdin
und/dev/stdout
auch auf die wenigen Betriebssysteme mit ihnen nicht)das Verhalten ähnlicher Programme nachahmen, indem die meisten ihrer Optionskonventionen wiederverwendet werden; insbesondere
-n
für Trockenlauf (à lamake
),-h
für Hilfe,-v
für Ausführlichkeit, etc ...Verwenden Sie
--
als Trennzeichen zwischen Optionen und Dateien oder anderen ArgumentenWenn Ihr Programm verwendet
isatty
, um zu testen, dass stdin ein Terminal ist (und sich in diesem Fall "interaktiv" verhält), stellen Sie eine Option bereit, um den nicht interaktiven Modus zu erzwingen, ebenso, wenn Ihr Programm eine GUI-Oberfläche hat (undgetenv("DISPLAY")
auf dem X11-Desktop testet ), dies aber auch könnte in Batch oder Kommandozeile verwendet werden.Einige Programme (z. B.
gcc
) akzeptieren indirekte Argumentlisten,@somefile.txt
dh, sie lesen Programmargumente aussomefile.txt
. Dies kann nützlich sein, wenn Ihr Programm sehr viele Argumente akzeptiert (mehr als die Ihres KernelsARG_MAX
).Übrigens können Sie sogar einige automatische Vervollständigungsfunktionen für Ihr Programm und übliche Shells (wie
bash
oderzsh
) hinzufügen.Einige alte Unix-Befehle (z. B.
dd
oder sogarsed
) haben seltsame Befehlsargumente für die historische Kompatibilität. Ich würde empfehlen, ihren schlechten Gewohnheiten nicht zu folgen (es sei denn, Sie machen eine bessere Variante davon).Wenn Ihre Software eine Reihe von zugehörigen Befehlszeilenprogramme, nehmen Inspiration von git (was Sie sicherlich als Entwicklungswerkzeug verwenden), die akzeptiert
git help
undgit --help
und haben vielegit
subcommand
undgit
subcommand
--help
In seltenen Fällen können Sie auch verwenden
argv[0]
(indem Sie Symlinks in Ihrem Programm verwenden), z. B.bash
aufgerufen, weilrbash
ein anderes Verhalten vorliegt ( eingeschränkte Shell). Aber normalerweise empfehle ich das nicht. Es kann sinnvoll sein, Ihr Programm als Skriptinterpreter mit shebang zu verwenden, dh#!
in der ersten Zeile, die von execve (2) interpretiert wird . Wenn Sie solche Tricks ausführen, müssen Sie sie dokumentieren, auch in--help
Nachrichten.Denken Sie daran , dass auf POSIX die Schale ist Globbing Argumente ( vor Ihrem Programm läuft!), So vermeiden Zeichen erfordern (wie
*
oder$
oder~
) in Optionen , die Shell-escaped sein müsste.In einigen Fällen können Sie einen Interpreter wie GNU Guile oder Lua in Ihre Software einbinden (vermeiden Sie es, Ihre eigene Turing-complete- Skriptsprache zu erfinden, wenn Sie keine Experten für Programmiersprachen sind). Dies hat tiefgreifende Konsequenzen für das Design Ihrer Software (sollte also frühzeitig bedacht werden!). Sie sollten dann problemlos in der Lage sein, ein Skript oder einen Ausdruck an diesen Interpreter zu übergeben. Wenn Sie diesen interessanten Ansatz wählen, sollten Sie Ihre Software und ihre interpretierten Grundelemente sorgfältig entwerfen. Sie könnten einige seltsame Benutzer haben, die große Skripte für Ihr Ding programmieren.
In anderen Fällen möchten Sie Ihre fortgeschrittenen Benutzer möglicherweise ihr Plugin in Ihre Software laden lassen (unter Verwendung dynamischer Ladetechniken à la
dlopen
&dlsym
). Auch dies ist eine sehr wichtige Entwurfsentscheidung (also definieren und dokumentieren Sie die Plugin-Oberfläche sorgfältig), und Sie müssen eine Konvention definieren, um Programmoptionen an diese Plugins zu übergeben.Wenn Ihre Software komplex ist, lassen Sie sie einige Konfigurationsdateien akzeptieren (zusätzlich oder anstelle von Programmargumenten) und haben möglicherweise die Möglichkeit, diese Konfigurationsdateien zu testen (oder nur zu analysieren), ohne den gesamten Code auszuführen. Beispielsweise ist ein Mail-Transfer-Agent (wie Exim oder Postfix) ziemlich komplex und es ist nützlich, ihn "halbtrocken" auszuführen (z. B. zu beobachten, wie er mit einer bestimmten E-Mail-Adresse umgeht, ohne tatsächlich eine E-Mail zu senden).
Beachten Sie, dass dies
/option
eine Windows- oder VMS-Sache ist. Auf POSIX-Systemen wäre dies verrückt (da die Dateihierarchie/
einen Verzeichnisseparator verwendet und die Shell das Globbing ausführt). Meine Antwort ist hauptsächlich für Linux (und POSIX).PS Wenn möglich, machen Sie Ihr Programm zu einer kostenlosen Software , Sie würden Verbesserungen von einigen Benutzern und Entwicklern erhalten (und das Hinzufügen einer neuen Programmoption ist oft eines der einfachsten Dinge, die Sie zu einer vorhandenen kostenlosen Software hinzufügen können). Auch hängt Ihre Frage viel von dem beabsichtigten Publikum : ein Spiel für Jugendliche oder ein Browser für Oma wahrscheinlich nicht die gleiche Art und Menge von Optionen als ein Compiler benötigt, oder einen Netzwerk - Inspektoren für Rechenzentrum sysadmins oder eine CAD - Software für den Mikroprozessor Architekten oder für Brückenbauer. Ein Ingenieur, der mit Programmieren und Skripten vertraut ist, mag wahrscheinlich viel mehr einstellbare Optionen als Ihre Oma und möchte möglicherweise Ihre Anwendung ohne X11 ausführen können (möglicherweise in einem
crontab
Job).quelle
git
ein besseres Beispiel. Ich würde es nicht empfehlen , sichcvs
2016 einmal umzusehen .dd -h
.--help
in der Regel, erkennen aber oft nicht,-h
was ärgerlich ist. Normalerweise gebe ich -h ein, wenn ich eine Option für ein Programm vergesse. Es ist ärgerlich, den Befehl mit der längeren Option erneut eingeben zu müssen--help
. Immerhin habe ich -h eingegeben, weil ich etwas vergessen habe. Warum sollte der Benutzer wissen, für welche Programme '--help' und für welche Programme '-h' erforderlich ist, um den Hilfebildschirm anzuzeigen? Fügen Sie einfach eine Option für -h und --help ein.Die Tatsache, dass eine Datenformatkonvention beliebt ist, ist ihr Vorteil.
Sie können leicht erkennen, dass die Verwendung von = oder: oder sogar '' als Trennzeichen triviale Unterschiede sind, die vom Computer mit geringem Aufwand ineinander umgewandelt werden können. Was für einen Menschen eine große Anstrengung wäre, ist sich zu erinnern: "Nun sehen Sie, hat dieses selten verwendete Programm die Dinge mit
:
oder mit begrenzt=
? Hmmm ..."Mit anderen Worten, weichen Sie aus Liebe zu Gott nicht ohne zwingenden Grund von extrem tief verwurzelten Konventionen ab. Die Leute werden sich an Ihr Programm als "das mit der seltsamen und nervigen cmdline-Syntax" erinnern, anstatt "das, das meinen College-Aufsatz gerettet hat".
quelle
dd
Verwendet einekey=value
Syntax. Der Grund für diese Entwurfsentscheidung ist, dass dieses Werkzeug (Spitzname: d ata d estroyer) bei falscher Verwendung viel Schaden anrichten kann. Indem sie den Benutzer zwingen, seine gewohnte Gewohnheit aufzugeben, zwingen sie den Benutzer, genauer darüber nachzudenken, was er tut.dd
? Ich glaube, dass es einfach zu einer Zeit (1970er Jahre?) Codiert wurde, als der ARG_MAX des Kernels klein war, Shells keine automatischen Vervollständigungen hatten und--long-arguments
nicht existierten. Seitdem besserdd
abwärtskompatibel gebliebendd
stammte aus einem anderen Betriebssystem (als UNIX) - einer Skriptsprache (JCL) unter IBM OS / 360 -, in der die Konventionen unterschiedlich waren, bevor sie mehr oder weniger unverändert auf UNIX portiert wurden - teilweise, weil diejenigen, die es wahrscheinlich verwenden, es von dem kannten vorheriges System.In Laienbegriffen
Wenn du in Rom bist, mach wie es die Römer tun.
-p value
oder--parameter value
. Linux verfügt über Tools, um solche Parameter und Flags auf einfache Weise zu analysieren.Normalerweise mache ich so etwas:
Wenn Ihre CLI-App für Windows vorgesehen ist, verwenden Sie
/flag
und/flag:value
Konventionen.Einige Apps wie Oracle verwenden jedoch keine. Oracle Dienstprogramme verwenden
PARAMETER=VALUE
.Eine Sache, die ich gerne mache, ist neben dem Akzeptieren von Parametern in der Befehlszeile die Option, eine Pardatei zu verwenden , bei der es sich um eine Schlüssel-Wert- Paardatei handelt , um lange Parameterketten zu vermeiden. Dafür sollten Sie einen zusätzlichen
--parfile mifile.par
Parameter angeben. Wenn--parfile
verwendet, werden natürlich alle anderen Parameter zugunsten des Inhalts der Parfile verworfen.Ein weiterer Vorschlag ist, die Verwendung einiger benutzerdefinierter Umgebungsvariablen zuzulassen. Wenn Sie beispielsweise Umgebungsvariablen
MYAPP_WRKSPACE=/tmp
festlegen, ist es nicht erforderlich, diese immer festzulegen--wrkspace /tmp
.TAB
und dann die Shell für sie ausführen.quelle
gcc
) behandeln@mifile.par
Ihre--parfile mifile.par
Vorschläge.fooCmd -opt1 -opt2 $(cat more_options.opts)
. Daher würde ich erwarten, dass eine "config file parameter" -Option, falls vorhanden, grundsätzlich auf die gleiche Weise funktioniert.Eine Sache, die noch nicht aufgetaucht ist:
Versuchen Sie, Ihre Software anhand der Befehlszeilenargumente nach oben zu entwerfen . Bedeutung:
Entwerfen Sie vor dem Entwerfen der Funktionalität die Benutzeroberfläche.
Auf diese Weise können Sie frühzeitig einen Drilldown zu Randfällen und allgemeinen Fällen durchführen. Natürlich werden Sie immer noch das Äußere und das Innere abstrahieren, aber es wird viel bessere Ergebnisse bringen, als nur den gesamten Code zu schreiben und dann eine CLI darauf zu knacken.
Schauen Sie sich außerdem docopt ( http://docopt.org/ ) an.
docopt ist dabei in vielen Sprachen eine große Hilfe, insbesondere bei Python, bei dem stark eingeschränkte, vom Benutzer unerwünschte Argument-Parser wie argparse weiterhin als "OK" eingestuft werden. Anstatt Parser und Subparser und Bedingungswörter zu haben, definieren Sie einfach die Syntaxhilfe, und der Rest wird erledigt.
quelle
argparse
, Programmierer, Benutzeroberfläche oder benutzerfreundlich zu sein.Einige wertvolle Kommentare (@Florian, Basile), aber lassen Sie mich hinzufügen ... OP sagt:
Aber auch Bemerkungen:
Sie müssen Ihre Zielgruppe berücksichtigen - fortgeschrittene Administratoren . Auf welcher Plattform arbeiten sie normalerweise - Win / Unix / Mac? Und auf welcher Plattform läuft deine App? Befolgen Sie die CLI-Konventionen, die bereits für diese Plattform festgelegt wurden. Wünschen / benötigen Ihre "fortgeschrittenen" Administratoren ein GUI-basiertes Tool?
Sie möchten, dass die Oberfläche intern und mit anderen Verwaltungstools konsistent ist. Ich will nicht aufhören und denken, ist es
cmd -p <arg>
odercmd -p:<arg>
odercmd /p <arg>
. Brauche ich Anführungszeichen, weil es ein Leerzeichen gibt? Kann ichcmd -p <val1> <val2>
odercmd -p <val1> -p <val2>
für mehrere Ziele? Sind sie auftragsspezifisch? Überladbar? Funktioniert dascmd -p2 <arg> -p1 <arg>
auch? Tutls -l -r -t dir1 dir2
==ls -trl dir1 dir2
?Bei meinen Unix-Admin-Tools habe ich immer die Anleitungen von Heiners Shelldorado sowie die anderen erwähnten Referenzen im Auge behalten.
Ebenso wichtig wie das Entwerfen der CLI ist es, sicherzustellen, dass Ihre Anwendung mit Befehlszeilenargumenten arbeitet, die mit denen der GUI identisch sind. Das heißt: Keine Geschäftslogik in der GUI oder Verwendung des allgemeinen Befehls, der sowohl von der GUI als auch von der CLI aufgerufen wird.
Die meisten UNIX-basierten Verwaltungstools sind eigentlich zuerst als Befehlszeilentools konzipiert, und die bereitgestellte GUI erleichtert lediglich das "Auffüllen" der Optionen für die Befehlszeile. Dieser Ansatz ermöglicht Automatisierung, Verwendung von Antwortdateien usw. und Hand-off-Management (weniger Arbeit für mich!)
Als klassisches Toolset wird hier Tcl / Tk verwendet . Nicht vorschlagen, dass Sie das Werkzeug wechseln; Betrachten Sie einfach den Entwurfsansatz, indem Sie zuerst eine GUI-basierte Verwaltungs-App als Befehlszeilen-Tool in die App schreiben. Legen Sie dann die GUI der Einfachheit halber auf. Irgendwann werden Sie wahrscheinlich feststellen, dass die grafische Benutzeroberfläche mühsam (und fehleranfällig) ist, wenn Sie mehrere Konfigurationen durchführen und im Allgemeinen immer wieder dieselben Optionen eingeben müssen, und Sie werden nach einem automatisierten Ansatz suchen.
Denken Sie daran, dass Ihr Administrator wahrscheinlich ohnehin die richtigen Werte in die richtigen Felder eingeben muss.
quelle