Lors du développement de l'application, j'ai commencé à me demander - Comment concevoir des arguments de ligne de commande?
De nombreux programmes utilisent une formule comme celle-ci -argument value
ou /argument value
. La solution qui m'est venue à l'esprit était argument:value
. Je pensais que c'était bien car sans espaces blancs, il n'y a aucun moyen de gâcher les valeurs et les arguments. Il est également facile de diviser une chaîne en deux sur la première à partir de la gauche :
personnage.
Mes questions sont:
-argument value
formule meilleure que argument:value
(plus lisible, plus facile à écrire, sans bug, plus facile à comprendre par les développeurs experts)?Interrogé pour plus de détails, je vous le fournirai. Cependant, je pense qu'ils ne devraient pas affecter les réponses. La question porte sur de bonnes habitudes en général. Je pense qu'ils sont tous les mêmes pour toutes sortes d'applications.
Nous travaillons sur une application qui sera utilisée dans les lieux publics (totems tactiles, tables). Les applications sont écrites à l'aide de Qt Quick 5 (C++, QML, JS). Windows 8.1/10 sera installé sur les appareils. Nous fournirons une interface frontale pour gérer les appareils. Cependant, certains administrateurs avancés peuvent souhaiter configurer l'application par eux-mêmes. Ce n'est pas très important du côté de l'entreprise, mais comme je suis d'accord avec ce que Kilian Foth a dit, je ne veux pas que mon application soit une douleur pour un utilisateur. Ne trouvant pas sur Internet ce que je veux, j'ai demandé ici.
Pour les utilisateurs plus avancés de Stack Exchange: je voulais que cette question soit générale. Peut-être qu'il se qualifie pour le wiki de la communauté (je ne sais pas si la question existante peut être convertie avec des réponses). Comme je veux que cette question soit indépendante du système d'exploitation et du langage de programmation, les réponses qui apparaissent ici peuvent être une leçon précieuse pour d'autres développeurs.
Sur les systèmes POSIX (par exemple Linux, MacOSX), au moins pour les programmes éventuellement démarrés dans un terminal Shell (par exemple la plupart d'entre eux), je recommanderais d'utiliser les conventions de codage GN (qui répertorie également les noms d'arguments courants) et examinez les directives des utilitaires POSIX , même pour les logiciels propriétaires:
toujours gérer --version
et --help
(même /bin/true
les accepte !!). Je maudis les auteurs de logiciels qui ne comprennent pas --help
, Je les déteste (car prog --help
Est la première commande que j'essaie sur un nouveau programme) ! Souvent, --help
Peut être abrégé en -h
Demandez au message --help
De répertorier toutes les options (sauf si vous en avez trop ... dans ce cas, répertoriez les plus courantes et explicitement faites référence à certains man
page ou une URL) et les valeurs par défaut des options, et peut-être des variables d'environnement importantes (et spécifiques au programme). Afficher ces listes d'options en cas d'erreur d'argument d'option.
accepter -a
argument court (lettre unique) et avoir un équivalent --long-argument
, donc -a2
--long-argument=2
, --long-argument 2
; bien sûr, vous pourriez avoir (pour les options rarement utilisées) un nom --only-long-argument
; pour les arguments modaux sans options supplémentaires -cf
est généralement traité comme -c -f
, etc. donc votre proposition -argument:value
est bizarre, et je ne recommande pas de le faire.
utilisez GLIBC getopt_long ou mieux (par exemple argp_parse , dans OCaml c'est Arg
module , ...)
utilise souvent -
pour l'entrée ou la sortie standard (si vous ne pouvez pas le faire, gérez /dev/stdin
& /dev/stdout
même sur les quelques systèmes d'exploitation qui n'en ont pas)
imite le comportement de programmes similaires en réutilisant la plupart de leurs conventions d'options; en particulier -n
pour la marche à sec (à la make
), -h
pour l'aide, -v
pour la verbosité, etc ...
utilisez --
comme séparateur entre les options et le fichier ou d'autres arguments
si votre programme utilise isatty
pour tester que stdin est un terminal (et se comporte "interactivement" dans ce cas), fournissez une option pour forcer le mode non interactif, de même si votre programme a une interface graphique (et teste getenv("DISPLAY")
sur le bureau X11) mais peut également être utilisé en batch ou en ligne de commande.
Certains programmes (par exemple gcc
) acceptent les listes d'arguments indirects, donc @somefile.txt
Signifie des arguments de programme lus dans somefile.txt
; cela peut être utile lorsque votre programme peut accepter un très grand nombre d'arguments (plus que le ARG_MAX
de votre noyau)
BTW, vous pouvez même ajouter des fonctionnalités de saisie semi-automatique pour votre programme et les shells habituels (comme bash
ou zsh
)
Certaines anciennes commandes Unix (par exemple dd
, ou même sed
) ont des arguments de commande étranges pour la compatibilité historique. Je recommanderais de ne pas suivre leurs mauvaises habitudes (sauf si vous en faites une meilleure variante).
Si votre logiciel est une série de programmes en ligne de commande, inspirez-vous de git (que vous utilisez sûrement comme outil de développement), qui accepte git help
Et git --help
et avoir plusieurs git
subcommand
et git
subcommand
--help
Dans de rares cas, vous pouvez également utiliser argv[0]
(En utilisant des liens symboliques sur votre programme), par exemple bash
appelé comme rbash
a un comportement différent ( restreint Shell). Mais je ne recommande généralement pas de faire cela; cela pourrait avoir du sens si votre programme pouvait être utilisé comme interpréteur de script en utilisant Shebang c'est-à-dire #!
sur la première ligne interprété par execve (2) . Si vous faites de telles astuces, assurez-vous de les documenter, y compris dans les messages --help
.
Souvenez-vous que sur POSIX le Shell est globbing arguments ( avant d'exécuter votre programme!), Donc évitez nécessitant des caractères (comme *
ou $
ou ~
) dans des options qui devraient être échappées par Shell.
Dans certains cas, vous pouvez intégrer un interpréteur comme GNU guile ou Lua dans votre logiciel (évitez d'inventer votre propre Turing-complete langage de script si vous ne sont pas experts en langages de programmation). Cela a des conséquences profondes sur la conception de votre logiciel (donc pensez-y tôt!). Vous devriez alors pouvoir facilement transmettre un script ou une expression à cet interprète. Si vous adoptez cette approche intéressante, concevez votre logiciel et ses primitives interprétées avec soin; vous pourriez avoir des utilisateurs étranges qui codent de gros scripts pour votre truc.
Dans d'autres cas, vous voudrez peut-être laisser vos utilisateurs avancés charger leur plugin dans votre logiciel (en utilisant chargement dynamique techniques à la dlopen
& dlsym
). Encore une fois, il s'agit d'une décision de conception très importante (définissez et documentez donc l'interface du plug-in avec soin), et vous devrez définir une convention pour transmettre les options du programme à ces plug-ins.
Si votre logiciel est une chose complexe, faites-le accepter fichiers de configuration (en plus ou en remplacement des arguments du programme) et avez probablement un moyen de tester (ou simplement analyser) ces fichiers de configuration sans exécuter tout le code . Par exemple, un agent de transfert de courrier (comme Exim ou Postfix) est assez complexe, et il est utile de pouvoir l'exécuter "à moitié sec" (par exemple en observant comment il gère une adresse e-mail donnée sans réellement envoyer d'e-mail).
Notez que le /option
Est une chose Windows ou VMS. Ce serait insensé sur les systèmes POSIX (parce que la hiérarchie des fichiers utilise /
Comme séparateur de répertoires, et parce que le shell effectue la globalisation). Toute ma réponse est principalement pour Linux (et POSIX).
P.S. Si possible, faites de votre programme un logiciel gratuit , vous obtiendrez des améliorations de la part de certains utilisateurs et développeurs (et l'ajout d'une nouvelle option de programme est souvent l'une des choses les plus faciles à ajouter à un logiciel gratuit existant). De plus, votre question dépend beaucoup du public visé : un jeu pour adolescents ou un navigateur pour grand-mère n'a probablement pas besoin du même type et de la même quantité d'options qu'un compilateur, ou un inspecteur de réseau pour les administrateurs système de centre de données, ou un logiciel CAD pour les architectes à microprocesseurs ou les concepteurs de ponts. Un ingénieur familier avec la programmation & les scripts aiment probablement beaucoup plus avoir beaucoup d'options réglables que votre grand-mère, et voudront probablement pouvoir exécuter votre application sans X11 (peut-être dans un travail crontab
).
Le fait qu'une convention de format de données soit populaire est son avantage.
Vous pouvez facilement voir que l'utilisation de = ou: ou même '' comme séparateur sont des différences triviales qui pourraient être converties les unes par les autres par ordinateur sans effort. Ce qui serait un gros effort est pour un humain de se souvenir "Maintenant, voyez-vous, ce programme rarement utilisé délimitait-il les choses avec :
ou avec =
? Hmmm ... "
En d'autres termes, pour l'amour de Dieu, ne déviez pas des conventions extrêmement bien ancrées sans raison impérieuse. Les gens se souviendront de votre programme comme "celui avec la syntaxe cmdline étrange et ennuyeuse" au lieu de "celui qui a sauvé mon essai collégial".
En termes simples
Quand à Rome, faites comme les Romains.
-p value
ou --parameter value
convention. Linux dispose d'outils pour analyser ces paramètres et indicateurs de manière simple.Je fais habituellement quelque chose comme ça:
while [[ $# > 0 ]]
do
key="$1"
case $key in
--dummy)
#this is a flag do something here
;;
--audit_sessiones)
#this is a flag do something here
;;
--destination_path)
# this is a key-value parameter
# the value is always in $2 ,
# you must shift to skip over for the next iteration
path=$2
shift
;;
*)
# unknown option
;;
esac
shift
done
Si votre application CLI est destinée à Windows, utilisez /flag
et /flag:value
conventions.
Certaines applications comme Oracle n'utilisent cependant ni l'un ni l'autre. Les utilitaires Oracle utilisent PARAMETER=VALUE
.
Une chose que j'aime faire est, en plus d'accepter des paramètres dans la ligne de commande, offrant la possibilité d'utiliser un parfile, qui est un fichier de paire clé-valeur pour éviter les longues chaînes de paramètres. Pour cela, vous devez fournir un --parfile mifile.par
paramètre. Évidemment, si --parfile
est utilisé, tous les autres paramètres sont supprimés au profit de ce qui se trouve à l'intérieur du parfile.
Une suggestion supplémentaire autorise l'utilisation de certaines variables d'environnement personnalisées, par exemple, en définissant la variable d'environnement MYAPP_WRKSPACE=/tmp
rendrait inutile de toujours définir --wrkspace /tmp
.
TAB
puis Shell le complétera pour eux.Une chose qui n'est pas encore apparue:
Essayez de concevoir votre logiciel à partir des arguments de la ligne de commande vers le haut. Sens:
Avant de concevoir la fonctionnalité, concevez l'interface utilisateur.
Cela vous permettra d'explorer les cas Edge et les cas courants très tôt. Bien sûr, vous abstiendrez toujours l'extérieur et l'intérieur, mais cela donnera de bien meilleurs résultats que d'écrire tout le code et de claquer une CLI dessus.
De plus, consultez docopt ( http://docopt.org/ ).
docopt est d'une grande aide pour cela dans de nombreuses langues, en particulier pour python où vous avez des analyseurs d'arguments très limités et défavorables pour l'utilisateur comme argparse toujours considérés comme "OK". Au lieu d'avoir des analyseurs et des sous-analyseurs et les dict conditionnels, il vous suffit de définir l'aide de la syntaxe et il fait le reste.
Certains commentaires précieux ont déjà été fournis (@Florian, Basile), mais permettez-moi d'ajouter ... OP dit,
Nous fournirons une interface frontale pour gérer les appareils. Cependant, certains administrateurs avancés peuvent souhaiter configurer l'application eux-mêmes
Mais remarque également:
Je ne voulais pas que cette question soit spécifique à la plate-forme ou à la langue
Vous devez considérer votre public cible - les administrateurs avancés . Sur quelle plateforme fonctionnent-ils normalement - Win/Unix/Mac? Et sur quelle plateforme votre application fonctionne-t-elle? Suivez les conventions CLI déjà établies pour cette plate-forme. Vos administrateurs "avancés" veulent/ont-ils besoin d'un outil basé sur une interface graphique?
Vous souhaitez que l'interface soit cohérente en interne et avec d'autres outils d'administration. Je ne veux pas m'arrêter et je pense que c'est cmd -p <arg>
ou cmd -p:<arg>
ou cmd /p <arg>
. Ai-je besoin de citations car il y a un espace? Puis-je cmd -p <val1> <val2>
ou cmd -p <val1> -p <val2>
pour plusieurs cibles? Sont-ils spécifiques à la commande? Surchargeable? Est-ce que cmd -p2 <arg> -p1 <arg>
travailler aussi? Est-ce que ls -l -r -t dir1 dir2
== ls -trl dir1 dir2
?
Pour mes outils d'administration Unix, j'ai toujours gardé à l'esprit les conseils fournis par Heiner's Shelldorado ainsi que les autres références mentionnées.
Aussi important que la conception de l'interface CLI est de vous assurer que votre application est conçue pour fonctionner avec des arguments de ligne de commande identiques à ceux de l'interface graphique - c'est-à-dire: pas de logique métier dans l'interface graphique ou utiliser la commande commune appelée à partir de l'interface graphique et de la CLI.
La plupart des outils d'administration basés sur UNIX sont en fait conçus d'abord comme des outils de ligne de commande et l'interface graphique fournie facilite simplement le "remplissage" des options de la ligne de commande. Cette approche permet l'automatisation, l'utilisation des fichiers de réponses, etc. et la gestion du transfert (moins de travail pour moi!)
Comme le jeu d'outils classique utilisé avec cette approche est Tcl/Tk . Ne pas suggérer de changer d'outils; il suffit de considérer l'approche de conception, de l'écriture d'une application d'administration basée sur une interface graphique à l'application en tant qu'outil de ligne de commande; puis superposez l'interface graphique pour plus de commodité. À un certain point, vous découvrirez probablement que l'interface graphique est une douleur (et sujette aux erreurs) si vous devez effectuer plusieurs configurations et ressaisir généralement les mêmes options encore et encore et que vous rechercherez une approche automatisée.
N'oubliez pas que votre administrateur doit probablement saisir les valeurs correctes dans les bonnes cases de toute façon, alors combien d'efforts soulagez-vous de toute façon avec l'interface graphique?