一个 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函数,请自行发挥想象力即可。

Top