option=value
Simplemente incluya argparse.hpp y estará listo.
# include < argparse/argparse.hpp >
Para comenzar a analizar argumentos de la línea de comandos, cree un ArgumentParser
.
argparse::ArgumentParser program ( " program_name " );
NOTA: Hay un segundo argumento opcional para ArgumentParser
que es la versión del programa. Ejemplo: argparse::ArgumentParser program("libfoo", "1.9.0");
NOTA: Hay un tercer y cuarto argumento opcional para ArgumentParser
que controla los argumentos predeterminados. Ejemplo: argparse::ArgumentParser program("libfoo", "1.9.0", default_arguments::help, false);
Consulte Argumentos predeterminados, a continuación.
Para agregar un nuevo argumento, simplemente llame .add_argument(...)
. Puede proporcionar una lista variada de nombres de argumentos que desea agrupar, por ejemplo, -v
y --verbose
program.add_argument( " foo " );
program.add_argument( " -v " , " --verbose " ); // parameter packing
Argparse admite una variedad de tipos de argumentos, incluidos argumentos posicionales, opcionales y compuestos. A continuación puedes ver cómo configurar cada uno de estos tipos:
A continuación se muestra un ejemplo de un argumento posicional :
# 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 ;
}
Y ejecutando el código:
foo@bar:/home/dev/ $ ./main 15
225
Esto es lo que está pasando:
add_argument()
se utiliza para especificar qué opciones de línea de comandos está dispuesto a aceptar el programa. En este caso lo he llamado cuadrado para que vaya acorde con su función..scan
para convertir la entrada del usuario en un número entero.parser.get<T>(key)
. Ahora, veamos los argumentos opcionales . Los argumentos opcionales comienzan con -
o --
, por ejemplo, --verbose
o -a
. Los argumentos opcionales se pueden colocar en cualquier lugar de la secuencia de entrada.
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
Esto es lo que está pasando:
--verbose
. Tenga en cuenta que al usar .default_value(false)
, si no se usa el argumento opcional, su valor se establece automáticamente en falso..implicit_value(true)
, el usuario especifica que esta opción es más una bandera que algo que requiere un valor. Cuando el usuario proporciona la opción --verbose, su valor se establece en verdadero. Al definir argumentos de bandera, puede usar la abreviatura flag()
que es lo mismo 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;
}
Hay escenarios en los que le gustaría hacer obligatorio un argumento opcional. Como se analizó anteriormente, los argumentos opcionales comienzan con -
o --
. Puede hacer que este tipo de argumentos sean necesarios de esta manera:
program.add_argument( " -o " , " --output " )
.required()
.help( " specify the output file. " );
Si el usuario no proporciona un valor para este parámetro, se genera una excepción.
Alternativamente, podrías proporcionar un valor predeterminado como este:
program.add_argument( " -o " , " --output " )
.default_value(std::string( " - " ))
.required()
.help( " specify the output file. " );
Si necesita que esté presente un argumento opcional pero no tiene un buen valor predeterminado, puede combinar las pruebas y el acceso al argumento de la siguiente manera:
if ( auto fn = program.present( " -o " )) {
do_something_with (*fn);
}
Al igual que get
, el método present
también acepta un argumento de plantilla. Pero en lugar de devolver T
, parser.present<T>(key)
devuelve std::optional<T>
, de modo que cuando el usuario no proporciona un valor para este parámetro, el valor devuelto se compara con std::nullopt
.
Si desea saber si el usuario proporcionó un valor para un argumento que tiene un .default_value
, verifique si el argumento .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
Es posible que desee permitir que se repita un argumento opcional y reunir todos los valores en un solo lugar.
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"}
Observe que .default_value
se le asigna un parámetro de plantilla explícito para que coincida con el tipo que desea .get
.
Un patrón común es repetir un argumento para indicar un valor mayor.
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
Cree un grupo mutuamente excluyente usando program.add_mutually_exclusive_group(required = false)
. `argparse`` se asegurará de que solo uno de los argumentos del grupo mutuamente excluyente esté presente en la línea de comando:
auto &group = program.add_mutually_exclusive_group();
group.add_argument( " --first " );
group.add_argument( " --second " );
con el siguiente uso producirá un error:
foo@bar:/home/dev/ $ ./main --first 1 --second 2
Argument '--second VAR' not allowed with '--first VAR'
La función add_mutually_exclusive_group()
también acepta un argumento required
, para indicar que se requiere al menos uno de los argumentos mutuamente excluyentes:
auto &group = program.add_mutually_exclusive_group( true );
group.add_argument( " --first " );
group.add_argument( " --second " );
con el siguiente uso producirá un error:
foo@bar:/home/dev/ $ ./main
One of the arguments '--first VAR' or '--second VAR' is required
Es posible vincular argumentos a una variable que almacene su valor, como alternativa a llamar explícitamente program.get<T>(arg_name)
o program[arg_name]
Actualmente, esto se implementa para variables de tipo bool
(esto también llama implícitamente flag()
), int
, double
, std::string
, std::vector<std::string>
y std::vector<int>
. Si el argumento no se especifica en la línea de comando, el valor predeterminado (si está establecido) se establece en 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);
Los argumentos opcionales comienzan con -
. ¿Puede argparse
manejar números negativos? ¡La respuesta es sí!
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
Como puede ver aquí, argparse
admite números enteros negativos, flotantes negativos y notación científica.
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 mensaje de ayuda, incluido el uso del programa e información sobre los argumentos registrados con ArgumentParser
. Para el ejemplo anterior, aquí está el mensaje de ayuda predeterminado:
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
También puede recibir el mensaje de ayuda en una cadena a través de program.help().str()
.
ArgumentParser::add_description
agregará texto antes de la información detallada del argumento. ArgumentParser::add_epilog
agregará texto después de todos los demás resultados de ayuda.
# 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.
Los objetos ArgumentParser normalmente asocian un único argumento de línea de comando con una única acción a realizar. El .nargs
asocia un número diferente de argumentos de línea de comandos con una sola acción. Cuando se usa nargs(N)
, N argumentos de la línea de comando se reunirán en una lista.
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>()
tiene especializaciones para std::vector
y std::list
. Entonces, la siguiente variante, .get<std::list>
, también funcionará.
auto files = program.get<std::list<std::string>>( " --input_files " ); // {"config.yml", "System.xml"}
Usando .scan
, uno puede crear rápidamente una lista de tipos de valores deseados a partir de argumentos de línea de comando. He aquí un ejemplo:
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}
También puede hacer una lista de argumentos de longitud variable con .nargs
. A continuación se muestran algunos ejemplos.
program.add_argument( " --input_files " )
.nargs( 1 , 3 ); // This accepts 1 to 3 arguments.
Algunos patrones útiles se definen como "?", "*", "+" de 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.
Los argumentos compuestos son argumentos opcionales que se combinan y se proporcionan como un único argumento. Ejemplo: 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}
Esto es lo que está pasando:
-a
, -b
y -c
.-a
y -b
son argumentos de alternancia.-c
requiere 2 números de punto flotante desde la línea de comando.-abc
o -bac
o -cab
. Esto sólo funciona con nombres de argumentos cortos de un solo carácter.-a
y -b
se vuelven verdaderos.-c
..default_value
Para las entradas, los usuarios pueden expresar un tipo primitivo para el valor.
El método .scan<Shape, T>
intenta convertir el std::string
entrante a T
siguiendo el especificador de conversión Shape
. Se lanza una excepción std::invalid_argument
o std::range_error
para los errores.
program.add_argument( " -x " )
.scan< ' d ' , int >();
program.add_argument( " scale " )
.scan< ' g ' , double >();
Shape
especifica cómo "se ve" la entrada y el argumento de plantilla de tipo especifica el valor de retorno de la acción predefinida. Los tipos aceptables son punto flotante (es decir, flotante, doble, doble largo) e integral (es decir, char con signo, corto, int, largo, largo, largo).
La gramática sigue std::from_chars
, pero no la duplica exactamente. Por ejemplo, los números hexadecimales pueden comenzar con 0x
o 0X
y los números con un cero a la izquierda pueden manejarse como valores octales.
Forma | interpretación |
---|---|
'una' o 'A' | punto flotante hexadecimal |
'e' o 'E' | notación científica (punto flotante) |
'f' o 'F' | notación fija (punto flotante) |
'g' o 'G' | forma general (ya sea fija o científica) |
'd' | decimal |
'i' | std::from_chars gramática con base == 10 |
'oh' | octal (sin firmar) |
'tú' | decimal (sin signo) |
'x' o 'X' | hexadecimal (sin firmar) |
argparse
proporciona argumentos y acciones predefinidos para -h
/ --help
y -v
/ --version
. De forma predeterminada, estas acciones saldrán del programa después de mostrar un mensaje de ayuda o de versión, respectivamente. Esta salida no llama a los destructores, omitiendo la limpieza de los recursos tomados.
Estos argumentos predeterminados se pueden desactivar durante la creación ArgumentParser
para que pueda manejarlos a su manera. (Tenga en cuenta que se debe incluir el nombre y la versión del programa al elegir los argumentos predeterminados).
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 );
El fragmento de código anterior genera un mensaje de ayuda y continúa ejecutándose. No admite un argumento --version
.
El valor predeterminado es default_arguments::all
para los argumentos incluidos. No se agregarán argumentos predeterminados con default_arguments::none
. default_arguments::help
y default_arguments::version
agregarán individualmente --help
y --version
.
Los argumentos predeterminados se pueden utilizar mientras se desactiva la salida predeterminada con estos argumentos. Este cuarto argumento de ArgumentParser
( exit_on_default_arguments
) es un indicador bool con un valor verdadero predeterminado. La siguiente llamada retendrá --help
y --version
, pero no saldrá cuando se utilicen esos argumentos.
argparse::ArgumentParser program ( " test " , " 1.0 " , default_arguments::all, false )
argparse
admite la recopilación de argumentos "restantes" al final del comando, por ejemplo, para usar en un compilador:
foo@bar:/home/dev/ $ compiler file1 file2 file3
Para habilitar esto, simplemente cree un argumento y márquelo como remaining
. Todos los argumentos restantes pasados a argparse se reúnen aquí.
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;
}
Cuando no se proporcionan argumentos:
foo@bar:/home/dev/ $ ./compiler
No files provided
y cuando se proporcionan múltiples argumentos:
foo@bar:/home/dev/ $ ./compiler foo.txt bar.txt baz.txt
3 files provided
foo.txt
bar.txt
baz.txt
El proceso de recopilar los argumentos restantes también funciona muy bien con los argumentos opcionales: