我想对我的程序实现子命令。我还需要为不同的子命令提供不同的参数选项。使用Boost.Program_options执行此操作的最佳方法是什么?
子命令用于svn,git和apt-get等程序。
例如,在GIT中,一些可用的子命令是:
git status
git push
git add
git pull
我的问题与这个人的问题基本相同:http://boost.2283326.n4.nabble.com/subcommands-with-program-options-like-svn-command-td2585537.html
答案 0 :(得分:45)
如果我正确理解了问题,您需要解析以下格式的命令行选项:
[--generic-option ...] cmd [--cmd-specific-option ... ]
这是我的示例解决方案。为了清楚起见,我将省略任何验证码,但希望你能看到如何简单地添加它。
在这个例子中,我们有" ls"子命令,可能还有其他人。每个子命令都有一些特定选项,此外还有通用选项。因此,让我们从解析通用选项和命令名开始。
po::options_description global("Global options");
global.add_options()
("debug", "Turn on debug output")
("command", po::value<std::string>(), "command to execute")
("subargs", po::value<std::vector<std::string> >(), "Arguments for command");
po::positional_options_description pos;
pos.add("command", 1).
add("subargs", -1);
po::variables_map vm;
po::parsed_options parsed = po::command_line_parser(argc, argv).
options(global).
positional(pos).
allow_unregistered().
run();
po::store(parsed, vm);
请注意,我们为命令名创建了一个位置选项,并为命令选项创建了多个位置选项。
现在我们分支相关的命令名并重新解析。我们现在以字符串数组的形式传入无法识别的选项,而不是传入原始的argc
和argv
。 collect_unrecognized
函数可以提供此功能 - 我们所要做的就是删除(位置)命令名称并使用相关的options_description
重新解析。
std::string cmd = vm["command"].as<std::string>();
if (cmd == "ls")
{
// ls command has the following options:
po::options_description ls_desc("ls options");
ls_desc.add_options()
("hidden", "Show hidden files")
("path", po::value<std::string>(), "Path to list");
// Collect all the unrecognized options from the first pass. This will include the
// (positional) command name, so we need to erase that.
std::vector<std::string> opts = po::collect_unrecognized(parsed.options, po::include_positional);
opts.erase(opts.begin());
// Parse again...
po::store(po::command_line_parser(opts).options(ls_desc).run(), vm);
请注意,对于特定于命令的选项,我们使用了与{1}相同的variables_map
。由此我们可以执行相关操作。
此处的代码片段取自可编译的源文件,其中包含一些单元测试。你可以在gist here上找到它。请随时下载并使用它。
答案 1 :(得分:3)
您可以使用位置选项从命令行中删除子命令名称 - 请参阅this tutorial。
似乎没有对子命令的任何内置支持 - 您需要在顶级解析器上设置allow_unregistered
选项,找到命令名称,然后通过第二个解析器运行它获取任何子命令特定的选项。