2013-03-21 39 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