一个 Linux 下的 CLI 程序
2017 年 11 月 23 日
工作需要,用C++做了一个交互式的CLI应用。其实nodejs和python都是做CLI的好工具,而且boilerplate也很多,但这次是因为里面有些代码需要直接搬运到其他平台使用。如果没有这个需求,就不用绑在C++上。
首先是起步,可以用这个boilerplate。注意这个boilerplate写的过于简略了,建议给Makefile增加变量,另外注意这个Makefile里忘了写target的依赖。
接下来是命令行参数处理,参考getopt_long的官方例子即可。
再下来是交互式命令行,这里可以参考stackoverflow上的一个问答。我这里增加了一点处理,就是做了一个函数指针的map,然后将命令和对应的函数预置在map中,写法是这样的(仅包括重点)。
//header part
typedef int(App::*FuncPointer)(); //函数指针,注意类名
std::map <std::string, FuncPointer> mCommandMap;
int RunCommand(std::string cmd);
int Exit();
int Command1();
int Command2();
//cpp constructor part
mCommandMap.insert(std::make_pair("q", &App::Exit));
mCommandMap.insert(std::make_pair("exit", &App::Exit));
mCommandMap.insert(std::make_pair("a", &App::Command1));
mCommandMap.insert(std::make_pair("b", &App::Command2));
//cpp run part
while(true) {
char* cmd = readline(“prompt> ”);
if (!cmd) {
break;
}
if (*cmd) {
add_history(cmd);
}
ret = application->RunCommand(cmd);
free(cmd);
if (ret < 0) {
return 0;
}
}
//RunCommand function
int App::RunCommand(std::string cmd) {
FuncPointer fp = mCommandMap[cmd];
if (fp) {
return (this->*fp)();
}
else {
if (cmd.compare("")) {
LOG("Unknown command \"%s\"", cmd.c_str());
}
return 0;
}
}
后面的部分就是具体的命令实现了,当然如果命令中带参数,那么需要修改RunCommand函数,请自行发挥想象力即可。