跨平台的命令行参数工具 — boost program_oprations
目录
1 例子
下例展示了 program_oprations 的基本用法:为程序定义了 3 个参数: help, host, port . 其中 host 与 port 分别定义了简写 h ,p 。host 是必填项, port 是有缺省值(80)的选填项,当 port 有输入时使用输入项,否则使用缺省值 ,当输入了错误的参数时会输出错误信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <iostream> #include "boost/program_options.hpp" using namespace boost; int main(int argc, char* argv[]) { program_options::options_description desc("Allowed options"); desc.add_options() ("help", "help") ("host,h", program_options::value<std::string>()->required(), "host name") ("port,p", program_options::value<int>()->default_value(80), "port number"); program_options::variables_map vm; try { auto ops = program_options::parse_command_line(argc, argv, desc); boost::program_options::store(ops, vm); } catch (boost::program_options::error& e) { std::cout << e.what() << std::endl; return 1; } if (vm.count("help")) { std::cout << desc << std::endl; } if (!vm.count("host")) { std::cout << "param is need : " << desc << std::endl; return 1; } //do sth ... std::cout << "Host is : " << vm["host"].as<std::string>() << ", Port is : " << vm["port"].as<int>() << std::endl; return 0; } |
测试效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
>testBoostProgramOptions.exe param is need : Allowed options: --help help -h [ --host ] arg host name -p [ --port ] arg (=80) port number >testBoostProgramOptions.exe -h 127.0.0.1 Host is : 127.0.0.1, Port is : 80 >testBoostProgramOptions.exe -h 127.0.0.1 -p 8080 Host is : 127.0.0.1, Port is : 8080 >testBoostProgramOptions.exe -h 127.0.0.1 -p 8080 -o er unrecognised option '-o' >testBoostProgramOptions.exe -p 8080 param is need : Allowed options: --help help -h [ --host ] arg host name -p [ --port ] arg (=80) port number |
progma_options 库由三部分组成:
descrition
, 描述组件,用于描述允许的参数及这些参数的值。parser
, 解析组件,用于解析输入的参数与值storage
, 存储组件, 它将解析器的输出转换成 字符串表示的健与 C++ 类型的值的 map, 并提供了访问这些值的接口。
对于上例来说, program_options 所做的事情,就是使用 options_description
描述了我们期望的参数,使用 parse_command_line
解析了输入参数并使用 store
将参数存储在 variables_map
中。当我们需要使用某个参数时直接从 variables_map
中获取。
2 description 描述组件
描述组件中有三个重要的类 : option_description
, value_semantic
和 options_description
. 前两个类组和使用来描述一个参数, option_description
包含了参数的 名称 ,描述 , 以及一个指向 value_semantic
对象的指针,这个指针对象定义了参数值的类型、可被解析的值、缺省值等信息。 而 options_description
则是 option_description
的容器。
一般地,我们添加一个参数时会先创建一个 option_description
对象,再使用 options_description
的 add
方法将参数添加到容器中:
1 2 |
auto descHost = boost::shared_ptr<program_options::option_description>("host", program_options::value<std::string>()->required(), "host name"); desc.add(descHost); |
如果参数比较多的话,使用这种方法就比较麻烦了。所以 boost 有特别的添加技巧:
1 2 3 4 5 |
program_options::options_description desc("Allowed options"); desc.add_options() ("help", "help") ("host,h", program_options::value<std::string>()->required(), "host name") ("port,p", program_options::value<int>()->default_value(80), "port number"); |
这看起来有点怪怪的,实际上这是对 operator( )
操作符重载的灵活运用。 options_description.add_options()
返回 options_description_easy_init
类的实例,该类重载了 "( )" 操作符,它模拟了 option_description
的构造函数,接收参数信息构造描述信息对象,添加到描述信息容器中,并返回其对象本身的引用,使其可以再次使用 "( )" 操作符来添加描述信息。
一个 option_description
实例可以分成两个部分: 语法 syntactic
和 语义 semantic
。语法信息规定用户输入参数的形式以及解析器解析的方式,包含参数名称与参数可以使用的符号(token) 的数量, 解析器会使用它将符号组成 (参数名,参数值)
这种形式的键值对,其中参数值是一组字符串( std::vector<std::string>
); 而语义信息则负责将参数值转换成合适的 C++ 类型。
2.1 语法信息
语法信息由 boost::program_options::options_description
类 和 boost::program_options::value_semantic
类的一些方法提供。句法信息包括:
参数名称
用于在程序中做变量标识参数描述
用于给用户以提示选项值可用的 token 数
将在解析时使用
如下示例:
1 2 3 4 5 6 |
options_description desc; desc.add_options() ("help", "produce help message") ("compression", value<string>(), "compression level") ("verbose", value<string>()->implicit_value("0"), "verbosity level") ("email", value<string>()->multitoken(), "email to send to"); |
这个示例中, help
不接受任何 token, compression
接收一个 token, verbose
可接受 0 个或 1 个 token, email
可以接受多个 token. 用户可以使用如下命令行:
1 |
test --help --compression 10 --verbose --email beadle@mars beadle2@mars |
2.2 语义信息
语义信息完全由 boost::program_options::value_semantic
类提供。 如下示例:
1 2 3 4 |
options_description desc; desc.add_options() ("compression", value<int>()->default_value(10), "compression level") ("email", value< vector<string> >()->composing(), "email"); |
可以使用如下命令行:
1 |
test --email a@b.com --compression 2 --email c@b.com |
在此例中, compression
将被解析成 2
, 如果没有输入此参数,那么 compression
将使用缺省值 10
。 而 email
参数则可以由多个值组合而成。
2.3 位置信息
位置参数是一种特殊的参数。如:
1 |
cat /etc/passwd |
这里 /etc/passwd
是没有参数名的。 当然,向前文一样,给它一个参数名也是可以的:
1 |
cat --input-file=/etc/passwd |
但 boost 提供了更优雅的解决方法: positional_options_description
类。该类可以指定:
- 允许使用多少个位置参数
- 每个位置参数的名称
- 每个位置参数的众多参数中的位置
如:
1 2 |
positional_options_description pd; pd.add("output-file", 2).add("input-file", -1); |
例中允许使用两个位置参数,第一个位置参数是参数中的第2个参数,名称为 "output-file", 第二个位置参数是参数中的倒数第一个参数,其名称为 "input-file"
3 parsers 解析器
顾名思义,解析器的作用就是将输入的命令行解析成程序可用的 (name,value)
键值对。由前几节可以知道,这个解析器依赖的解析规则是由 描述组件
来确定的。如果不符合描述则会抛出异常。除了通过一般的描述信息来解析,还有以下几种特殊的情况:
- 参数名称使用了
简写
(或称 ="别名"= ) - 一个参数名有多个参数值的(如上例中的 email )
- 命令行中包含了
positional
信息的,见上节内容
常用的解析方法有:
program_options::parse_command_line()
,解析命令行program_options::parse_config_file()
, 解析配置文件program_options::parse_environment()
, 解析环境变量
3.1 Configuration file parser
parse_config_file
方法可以解析类似 INI
风格的配置文件。这种风格以行为单位,一行即为一组参数。当然,还有两种特殊情况:
- 以括号
[ ]
修饰的行 ,表示一个新的 section - 以
#
修饰的注释, 从#
符号开始到行结束,都为注释
例如:
1 2 3 4 5 |
host=wandoer.com #host_name [user.info] # new section name=zrking email=a@b.com #the end of config_file |
这些配置与下面的配置是等价的:
1 2 3 |
host=wandoer.com user.info.name=zrking user.info.email=a@b.com |
//待续