option=value
Incluez simplement argparse.hpp et vous êtes prêt à partir.
# include < argparse/argparse.hpp >
Pour commencer à analyser les arguments de ligne de commande, créez un ArgumentParser
.
argparse::ArgumentParser program ( " program_name " );
REMARQUE : Il existe un deuxième argument facultatif pour ArgumentParser
qui correspond à la version du programme. Exemple : argparse::ArgumentParser program("libfoo", "1.9.0");
REMARQUE : Il existe des troisième et quatrième arguments facultatifs pour ArgumentParser
qui contrôlent les arguments par défaut. Exemple : argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);
Voir Arguments par défaut ci-dessous.
Pour ajouter un nouvel argument, appelez simplement .add_argument(...)
. Vous pouvez fournir une liste variadique de noms d'arguments que vous souhaitez regrouper, par exemple -v
et --verbose
program.add_argument( " foo " );
program.add_argument( " -v " , " --verbose " ); // parameter packing
Argparse prend en charge une variété de types d'arguments, notamment les arguments positionnels, facultatifs et composés. Ci-dessous, vous pouvez voir comment configurer chacun de ces types :
Voici un exemple d' argument positionnel :
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " program_name " );
program. add_argument ( " square " )
. help ( " display the square of a given integer " )
. scan < ' i ' , int >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
return 1 ;
}
auto input = program. get < int >( " square " );
std::cout << (input * input) << std::endl;
return 0 ;
}
Et en exécutant le code :
foo@bar:/home/dev/ $ ./main 15
225
Voici ce qui se passe :
add_argument()
est utilisée pour spécifier les options de ligne de commande que le programme est prêt à accepter. Dans ce cas, je l'ai nommé carré pour qu'il corresponde à sa fonction..scan
pour convertir les entrées de l'utilisateur en un entier.parser.get<T>(key)
. Voyons maintenant les arguments facultatifs . Les arguments facultatifs commencent par -
ou --
, par exemple --verbose
ou -a
. Les arguments facultatifs peuvent être placés n'importe où dans la séquence d'entrée.
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
foo@bar:/home/dev/ $ ./main --verbose
Verbosity enabled
Voici ce qui se passe :
--verbose
. Notez qu'en utilisant .default_value(false)
, si l'argument facultatif n'est pas utilisé, sa valeur est automatiquement définie sur false..implicit_value(true)
, l'utilisateur spécifie que cette option est plus un indicateur que quelque chose qui nécessite une valeur. Lorsque l'utilisateur fournit l'option --verbose, sa valeur est définie sur true. Lors de la définition des arguments du drapeau, vous pouvez utiliser le raccourci flag()
qui est le même que default_value(false).implicit_value(true)
.
argparse::ArgumentParser program ( " test " );
program.add_argument( " --verbose " )
.help( " increase output verbosity " )
.flag();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
if (program[ " --verbose " ] == true ) {
std::cout << " Verbosity enabled " << std::endl;
}
Il existe des scénarios dans lesquels vous souhaiteriez rendre obligatoire un argument facultatif. Comme indiqué ci-dessus, les arguments facultatifs commencent par -
ou --
. Vous pouvez rendre ces types d’arguments obligatoires comme suit :
program.add_argument( " -o " , " --output " )
.required()
.help( " specify the output file. " );
Si l'utilisateur ne fournit pas de valeur pour ce paramètre, une exception est levée.
Alternativement, vous pouvez fournir une valeur par défaut comme celle-ci :
program.add_argument( " -o " , " --output " )
.default_value(std::string( " - " ))
.required()
.help( " specify the output file. " );
Si vous avez besoin d'un argument facultatif mais que vous n'avez pas de bonne valeur par défaut, vous pouvez combiner les tests et l'accès à l'argument comme suit :
if ( auto fn = program.present( " -o " )) {
do_something_with (*fn);
}
Semblable à get
, la méthode present
accepte également un argument de modèle. Mais plutôt que de renvoyer T
, parser.present<T>(key)
renvoie std::optional<T>
, de sorte que lorsque l'utilisateur ne fournit pas de valeur à ce paramètre, la valeur de retour est égale à std::nullopt
.
Si vous voulez savoir si l'utilisateur a fourni une valeur pour un argument qui a un .default_value
, vérifiez si l'argument .is_used()
.
program.add_argument( " --color " )
.default_value(std::string{ " orange " }) // might otherwise be type const char* leading to an error when trying program.get<std::string>
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color orange
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto color = program.get<std::string>( " --color " ); // "orange"
auto explicit_color = program.is_used( " --color " ); // true, user provided orange
Vous souhaiterez peut-être autoriser la répétition d’un argument facultatif et rassembler toutes les valeurs au même endroit.
program.add_argument( " --color " )
.default_value<std::vector<std::string>>({ " orange " })
.append()
.help( " specify the cat's fur color " );
try {
program. parse_args (argc, argv); // Example: ./main --color red --color green --color blue
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto colors = program.get<std::vector<std::string>>( " --color " ); // {"red", "green", "blue"}
Notez que .default_value
reçoit un paramètre de modèle explicite pour correspondre au type que vous souhaitez .get
.
Un modèle courant consiste à répéter un argument pour indiquer une valeur plus élevée.
int verbosity = 0 ;
program.add_argument( " -V " , " --verbose " )
.action([&]( const auto &) { ++verbosity; })
.append()
.default_value( false )
.implicit_value( true )
.nargs( 0 );
program.parse_args(argc, argv); // Example: ./main -VVVV
std::cout << " verbose level: " << verbosity << std::endl; // verbose level: 4
Créez un groupe mutuellement exclusif à l'aide de program.add_mutually_exclusive_group(required = false)
. `argparse`` s'assurera qu'un seul des arguments du groupe mutuellement exclusif était présent sur la ligne de commande :
auto &group = program.add_mutually_exclusive_group();
group.add_argument( " --first " );
group.add_argument( " --second " );
avec l'utilisation suivante générera une erreur :
foo@bar:/home/dev/ $ ./main --first 1 --second 2
Argument '--second VAR' not allowed with '--first VAR'
La fonction add_mutually_exclusive_group()
accepte également un argument required
, pour indiquer qu'au moins un des arguments mutuellement exclusifs est requis :
auto &group = program.add_mutually_exclusive_group( true );
group.add_argument( " --first " );
group.add_argument( " --second " );
avec l'utilisation suivante générera une erreur :
foo@bar:/home/dev/ $ ./main
One of the arguments '--first VAR' or '--second VAR' is required
Il est possible de lier des arguments à une variable stockant leur valeur, au lieu d'appeler explicitement program.get<T>(arg_name)
ou program[arg_name]
Ceci est actuellement implémenté pour les variables de type bool
(cela appelle également implicitement flag()
), int
, double
, std::string
, std::vector<std::string>
et std::vector<int>
. Si l'argument n'est pas spécifié dans la ligne de commande, la valeur par défaut (si définie) est définie dans la variable.
bool flagvar = false ;
program.add_argument( " --flagvar " ).store_into(flagvar);
int intvar = 0 ;
program.add_argument( " --intvar " ).store_into(intvar);
double doublevar = 0 ;
program.add_argument( " --doublevar " ).store_into(doublevar);
std::string strvar;
program.add_argument( " --strvar " ).store_into(strvar);
std::vector<std::string> strvar_repeated;
program.add_argument( " --strvar-repeated " ).append().store_into(strvar_repeated);
std::vector<std::string> strvar_multi_valued;
program.add_argument( " --strvar-multi-valued " ).nargs( 2 ).store_into(strvar_multi_valued);
std::vector< int > intvar_repeated;
program.add_argument( " --intvar-repeated " ).append().store_into(intvar_repeated);
std::vector< int > intvar_multi_valued;
program.add_argument( " --intvar-multi-valued " ).nargs( 2 ).store_into(intvar_multi_valued);
Les arguments facultatifs commencent par -
. argparse
peut-il gérer les nombres négatifs ? La réponse est oui !
argparse::ArgumentParser program;
program.add_argument( " integer " )
.help( " Input number " )
.scan< ' i ' , int >();
program.add_argument( " floats " )
.help( " Vector of floats " )
.nargs( 4 )
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
// Some code to print arguments
foo@bar:/home/dev/ $ ./main -5 -1.1 -3.1415 -3.1e2 -4.51329E3
integer : -5
floats : -1.1 -3.1415 -310 -4513.29
Comme vous pouvez le voir ici, argparse
prend en charge les entiers négatifs, les flottants négatifs et la notation scientifique.
argparse::ArgumentParser program ( " main " );
program.add_argument( " square " )
.help( " display the square of a given number " )
.scan< ' i ' , int >();
program.add_argument( " --verbose " )
.default_value( false )
.implicit_value( true );
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
int input = program.get< int >( " square " );
if (program[ " --verbose " ] == true ) {
std::cout << " The square of " << input << " is " << (input * input) << std::endl;
}
else {
std::cout << (input * input) << std::endl;
}
foo@bar:/home/dev/ $ ./main 4
16
foo@bar:/home/dev/ $ ./main 4 --verbose
The square of 4 is 16
foo@bar:/home/dev/ $ ./main --verbose 4
The square of 4 is 16
std::cout << program
imprime un message d'aide, comprenant l'utilisation du programme et des informations sur les arguments enregistrés avec ArgumentParser
. Pour l'exemple précédent, voici le message d'aide par défaut :
foo@bar:/home/dev/$ ./main --help
Usage: main [-h] [--verbose] square
Positional arguments:
square display the square of a given number
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--verbose
Vous pouvez également obtenir le message d'aide sous forme de chaîne via program.help().str()
.
ArgumentParser::add_description
ajoutera du texte avant les informations détaillées sur l'argument. ArgumentParser::add_epilog
ajoutera du texte après toutes les autres sorties d'aide.
# include < argparse/argparse.hpp >
int main ( int argc, char *argv[]) {
argparse::ArgumentParser program ( " main " );
program. add_argument ( " thing " ). help ( " Thing to use. " ). metavar ( " THING " );
program. add_argument ( " --member " ). help ( " The alias for the member to pass to. " ). metavar ( " ALIAS " );
program. add_argument ( " --verbose " ). default_value ( false ). implicit_value ( true );
program. add_description ( " Forward a thing to the next member. " );
program. add_epilog ( " Possible things include betingalw, chiz, and res. " );
program. parse_args (argc, argv);
std::cout << program << std::endl;
}
Usage: main [-h] [--member ALIAS] [--verbose] THING
Forward a thing to the next member.
Positional arguments:
THING Thing to use.
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--member ALIAS The alias for the member to pass to.
--verbose
Possible things include betingalw, chiz, and res.
Les objets ArgumentParser associent généralement un seul argument de ligne de commande à une seule action à entreprendre. Le .nargs
associe un nombre différent d'arguments de ligne de commande à une seule action. Lors de l'utilisation nargs(N)
, N arguments de la ligne de commande seront rassemblés dans une liste.
argparse::ArgumentParser program ( " main " );
program.add_argument( " --input_files " )
.help( " The list of input files " )
.nargs( 2 );
try {
program. parse_args (argc, argv); // Example: ./main --input_files config.yml System.xml
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto files = program.get<std::vector<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
ArgumentParser.get<T>()
a des spécialisations pour std::vector
et std::list
. Ainsi, la variante suivante, .get<std::list>
, fonctionnera également.
auto files = program.get<std::list<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
En utilisant .scan
, on peut rapidement créer une liste de types de valeurs souhaités à partir d'arguments de ligne de commande. Voici un exemple :
argparse::ArgumentParser program ( " main " );
program.add_argument( " --query_point " )
.help( " 3D query point " )
.nargs( 3 )
.default_value(std::vector< double >{ 0.0 , 0.0 , 0.0 })
.scan< ' g ' , double >();
try {
program. parse_args (argc, argv); // Example: ./main --query_point 3.5 4.7 9.2
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto query_point = program.get<std::vector< double >>( " --query_point " ); // {3.5, 4.7, 9.2}
Vous pouvez également créer une liste d'arguments de longueur variable avec le .nargs
. Voici quelques exemples.
program.add_argument( " --input_files " )
.nargs( 1 , 3 ); // This accepts 1 to 3 arguments.
Certains modèles utiles sont définis comme "?", "*", "+" d'argparse en Python.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::any); // "*" in Python. This accepts any number of arguments including 0.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::at_least_one); // "+" in Python. This accepts one or more number of arguments.
program.add_argument( " --input_files " )
.nargs(argparse::nargs_pattern::optional); // "?" in Python. This accepts an argument optionally.
Les arguments composés sont des arguments facultatifs qui sont combinés et fournis sous forme d'argument unique. Exemple : ps -aux
argparse::ArgumentParser program ( " test " );
program.add_argument( " -a " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -b " )
.default_value( false )
.implicit_value( true );
program.add_argument( " -c " )
.nargs( 2 )
.default_value(std::vector< float >{ 0 . 0f , 0 . 0f })
.scan< ' g ' , float >();
try {
program. parse_args (argc, argv); // Example: ./main -abc 1.95 2.47
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
auto a = program.get< bool >( " -a " ); // true
auto b = program.get< bool >( " -b " ); // true
auto c = program.get<std::vector< float >>( " -c " ); // {1.95, 2.47}
// / Some code that prints parsed arguments
foo@bar:/home/dev/ $ ./main -ac 3.14 2.718
a = true
b = false
c = {3.14, 2.718}
foo@bar:/home/dev/ $ ./main -cb
a = false
b = true
c = {0.0, 0.0}
Voici ce qui se passe :
-a
, -b
et -c
.-a
et -b
sont des arguments à bascule.-c
nécessite 2 nombres à virgule flottante à partir de la ligne de commande.-abc
ou -bac
ou -cab
. Cela ne fonctionne qu'avec des noms d'arguments courts à un seul caractère.-a
et -b
deviennent vrais.-c
..default_value
Pour les entrées, les utilisateurs peuvent exprimer un type primitif pour la valeur.
La méthode .scan<Shape, T>
tente de convertir le std::string
entrant en T
en suivant le spécificateur de conversion Shape
. Une exception std::invalid_argument
ou std::range_error
est levée pour les erreurs.
program.add_argument( " -x " )
.scan< ' d ' , int >();
program.add_argument( " scale " )
.scan< ' g ' , double >();
Shape
spécifie à quoi "ressemble" l'entrée et l'argument du modèle de type spécifie la valeur de retour de l'action prédéfinie. Les types acceptables sont les suivants : virgule flottante (c'est-à-dire float, double, long double) et intégrale (c'est-à-dire signed char, short, int, long, long long).
La grammaire suit std::from_chars
, mais ne la duplique pas exactement. Par exemple, les nombres hexadécimaux peuvent commencer par 0x
ou 0X
et les nombres avec un zéro non significatif peuvent être traités comme des valeurs octales.
Forme | interprétation |
---|---|
'un' ou 'A' | virgule flottante hexadécimale |
'e' ou 'E' | notation scientifique (virgule flottante) |
'f' ou 'F' | notation fixe (virgule flottante) |
'g' ou 'G' | forme générale (fixe ou scientifique) |
'd' | décimal |
'je' | std::from_chars grammaire avec base == 10 |
'o' | octal (non signé) |
'tu' | décimal (non signé) |
'x' ou 'X' | hexadécimal (non signé) |
argparse
fournit des arguments et des actions prédéfinis pour -h
/ --help
et -v
/ --version
. Par défaut, ces actions quitteront le programme après avoir affiché respectivement un message d'aide ou de version. Cette sortie n'appelle pas de destructeurs, ignorant le nettoyage des ressources utilisées.
Ces arguments par défaut peuvent être désactivés lors de la création ArgumentParser
afin que vous puissiez gérer ces arguments à votre manière. (Notez qu'un nom et une version du programme doivent être inclus lors du choix des arguments par défaut.)
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::none);
program.add_argument( " -h " , " --help " )
.action([=]( const std::string& s) {
std::cout << help (). str ();
})
.default_value( false )
.help( " shows help message " )
.implicit_value( true )
.nargs( 0 );
L'extrait de code ci-dessus génère un message d'aide et continue de s'exécuter. Il ne prend pas en charge l'argument --version
.
La valeur par défaut est default_arguments::all
pour les arguments inclus. Aucun argument par défaut ne sera ajouté avec default_arguments::none
. default_arguments::help
et default_arguments::version
ajouteront individuellement --help
et --version
.
Les arguments par défaut peuvent être utilisés tout en désactivant la sortie par défaut avec ces arguments. Ce quatrième argument d' ArgumentParser
( exit_on_default_arguments
) est un indicateur booléen avec une valeur vraie par défaut. L'appel suivant conservera --help
et --version
, mais ne se terminera pas lorsque ces arguments seront utilisés.
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::all, false )
argparse
prend en charge la collecte des arguments "restants" à la fin de la commande, par exemple pour une utilisation dans un compilateur :
foo@bar:/home/dev/ $ compiler file1 file2 file3
Pour activer cela, créez simplement un argument et marquez-le comme remaining
. Tous les arguments restants transmis à argparse sont rassemblés ici.
argparse::ArgumentParser program ( " compiler " );
program.add_argument( " files " )
.remaining();
try {
program. parse_args (argc, argv);
}
catch ( const std:: exception & err) {
std::cerr << err. what () << std::endl;
std::cerr << program;
std::exit ( 1 );
}
try {
auto files = program. get <std::vector<std::string>>( " files " );
std::cout << files. size () << " files provided " << std::endl;
for ( auto & file : files)
std::cout << file << std::endl;
} catch (std::logic_error& e) {
std::cout << " No files provided " << std::endl;
}
Lorsqu'aucun argument n'est fourni :
foo@bar:/home/dev/ $ ./compiler
No files provided
et lorsque plusieurs arguments sont fournis :
foo@bar:/home/dev/ $ ./compiler foo.txt bar.txt baz.txt
3 files provided
foo.txt
bar.txt
baz.txt
Le processus de collecte des arguments restants fonctionne également bien avec les arguments facultatifs :