簡介
如果使用比較多的命令行程序的話,對於命令行參數的輸入肯定不會陌生,大部分的程序都是通過類似下面的形式進行輸入的,比如熟悉的ls
ls --all -l --color=auto
這里面包含了三種不同的命令行輸入--all
,-l
和--color=auto
。如果使用一般的解決方法的話,是使用getopt.h
文件中的getopt
函數。其具體的教程可以看Linux下getopt()函數的簡單使用,其使用方法比較麻煩。而且只支持一個字符的選項,如果要像--color=auto
一樣支持長選項,必須再使用getopt_long
函數,而且由於其是對C進行支持的,所以在C++中使用起來也比較麻煩。
而Boost提供的Program_options庫可以很好的解決這一問題。Program_options提供了一個成熟的C++庫來解析命令行參數,幾行簡單清晰的代碼就可以描繪出一個完整的命令行解析器。
而其的使用方法也是非常的簡單,大致可以分為三個部分,構建解析器對象,解析命令行參數,使用結果。
使用的時候需要鏈接boost_program_options庫
沒有參數的選項
一個非常簡單的例子,只定義了一個選項help
,運行時會直接先打印獲取到的var_map
的name
,然后檢查是否存在help
選項,如果存在則打印命令行幫助,如果不存在,就直接推出。
#include <boost/program_options.hpp>
#include <iostream>
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
boost::program_options::options_description desc("測試程序");
desc.add_options()("help,h", "打印幫助文檔");
boost::program_options::variables_map var_map;
boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), var_map);
boost::program_options::notify(var_map);
for (auto iter : var_map) {
std::cout << iter.first << std::endl;
}
if (var_map.count("help") > 0) std::cout << desc << std::endl;
return 0;
}
編譯以后運行./main_simple -h
或者./main_simple --help
可以得到:
help
測試程序:
-h [ --help ] 打印幫助文檔
首先是定義了一個boost::program_options::options_description
對象,它可以選項列表的描述。它的構造函數可以傳入一個字符串,作為打印時候的抬頭。
然后是向選項列表里面添加選項,最簡單的方法就是使用desc
對象里面的add_options
方法,它可以返回一個函數對象,借此向選項列表描述添加選項。
目前在這里的選項列表只有簡單的兩個參數,第一個是表明選項的name
,你可以通過用分號將長選項和縮寫分割開來,而最終的結果還是以長選項作為name
的;第二個是對選項的描述。
然后定義了一個boost::program_options::variables_map
對象,它是一個map
,key元素為選項的name
,value元素為Boost::any
對象。
然后開始對命令行輸入進行解析,首先使用boost::program_options::parse_command_line
進行解析,然后使用boost::program_options::store
將結果保存在var_map
變量里面。
boost::program_options::notify
將在后面提到。
接下來,就是對map
的操作了。而如果想輸出說明的話,也可以很直接的直接對desc
進行cout
。
帶參數的選項
上面我們介紹了不帶參數的簡單使用,但是在很多的時候,我們需要通過命令行輸入一些參數。就如同最上面例子中的--color=auto
一樣。Boost提供了非常簡單的方法來實現這一操作。
#include <vector>
#include <string>
#include <iostream>
#include <boost/program_options.hpp>
int main(int argc, char *argv[]) {
boost::program_options::options_description desc("測試程序");
desc.add_options()("help,h", "打印幫助文檔");
desc.add_options()("input,i", boost::program_options::value<std::string>()->default_value("Test")->value_name("string"), "輸入");
boost::program_options::variables_map var_map;
boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), var_map);
boost::program_options::notify(var_map);
if (var_map.count("help") > 0) std::cout << desc << std::endl;
if (var_map.count("input") > 0) std::cout << var_map["input"].as<std::string>() << std::endl;
return 0;
}
在這個程序中,增加了一行
desc.add_options()("input,i", boost::program_options::value<std::string>()->default_value("Test")->value_name("string"), "輸入");
和之前的help
選項類似,在這里我們增加了一個input
選項,在這個添加過程中,我們向函數對象添加了3個參數,第一個和第三個參數和之前表述的一樣。而第二個參數可以看作是對輸入的描述。
首先我們通過boost::program_options::value
構造了一個對象,在構造的過程中,需要向模板傳入一個類型參數,表表明輸入值的類型。然后其會構造出一個boost::program_options::type_value
類型,可以通過一些方法對其進行設置。
在這一示例中,用戶可以在input
后面輸入一個字符串,同時如果沒有輸入的話,會主動出現一個默認值Test
,這個默認值會在沒有輸入的時候作為input
項的默認值。
然后可以通過對var_map
進行簡單的操作,來獲取輸入的值。
輸入數組
如果一個選項我們需要多次輸入需要如何處理呢?比如exec.bin -i test -i test1
。
這一個的處理比較簡單,和上面的程序相比,我們只需要將input
選項的值修改為std::vector
就可以了,即:
C++ desc.add_options()("input,i", boost::program_options::value<std::vector<std::string>>()->value_name("string"), "輸入");
相應的,我們的輸出改為
auto input_s = var_map["input"].as<std::vector<std::string>>();
for (auto inputm : input_s) {
std::cout << inputm << std::endl;
}
如果想不用重復鍵入-i
,而是直接在同一個輸入用空格隔開不同的值,如exec.bin -i test test1
,那么可以考慮為屬性增加multitoken
desc.add_options()("input,i", boost::program_options::value<std::vector<std::string>>()->multitoken(), "輸入");
其他雜項
很明顯,Boost.Program_options的操作肯定還不止這一些,但是以上的簡單操作,基本上可以覆蓋大部分的使用場景了。然后還有一些使用的小細節。
報錯
如果輸入的選項中存在描述中沒有的選項的話,就會在解析的時候產生一個異常,可以通過捕捉這一個異常,給程序一個更加合理的表現。
隱藏項
如果想給程序增加一個“后門”,只有你知道的選項,應該如何操作呢?
其實很簡單,建立兩個options_description
就好了,一個用來顯示,一個用來解析。這樣就不會在顯示的時候,顯示需要隱藏的項了。