2013-03-21 34 views
20

我想实现子程序到我的程序。我还需要为不同的子命令提供不同的参数选项。使用Boost.Program_options执行此操作的最佳方法是什么?如何使用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

回答

38

如果我理解正确的问题,要分析以下形式的命令行选项:

[--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); 

请注意,我们为命令名称和命令选项创建了多个位置选项。

现在我们分支到相关的命令名并重新解析。我们现在不用传入原始的argcargv,而是以字符串数组的形式传递无法识别的选项。 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); 

请注意,我们使用相同的variables_map有特定命令的选项作为通用的。由此我们可以执行相关操作。

这里的代码段来自一个可编译源文件,其中包含一些单元测试。你可以找到它的要求here。请随意下载并使用它。

+1

优秀的答案,以完整的例子来启动。谢谢! --DD – ddevienne 2014-06-23 11:56:38

+0

太棒了! – 2015-01-16 17:30:41

3

您可以乘坐子的名字从命令行中使用位置选项 - 见this tutorial

似乎没有任何对子命令的内置支持 - 您需要在顶级解析器上设置allow_unregistered选项,找到命令名,然后通过第二个解析器运行它以获取任何子命令 - 特定选项。

+2

我无法使此解决方案正常工作。特别是,Boost似乎不希望在位置选项之后允许任何事情发生。因此,即使使用allow_unregistered,boost也抱怨位置选项太多(即“命令行上指定的位置选项过多”),即使这些位置选项应该由子选项解析,命令。 – nomad 2013-05-13 19:27:43