Linux命令行參數解析——getopt_long

  • 在linux中,一切皆文件,所有的可執行程序都可以通過命令行啓動,程序啓動時通常都會帶上各種參數以控制程序的行爲。所以解析命令行參數通常是一個可執行程序的第一步,下面就來介紹下經常用到的命令行參數的解析函數——getopt_long。

  • 我們先來了解一下命令行參數。命令行參數可以分爲兩類,一類是短選項,一類是長選項。在命令行中"-"表示短選項,"--"則表示長選項。例如,在linux中最常用的ls命令中“-a,-A,-b”都是短選項,而它們對應的長選項則是“--all,--almost-all, --escape”。它們還都可選擇性的添加額外參數,比如“--block-size=SIZE”。

  • getopt_long支持處理長短選項的命令行解析,函數在<getopt.h>頭文件中。其函數定義是:

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); 
  • 接下來介紹一下其參數以及返回值。

    • argc和argv和main函數的兩個參數一致。
    • optstring: 表示短選項字符串。
      形式如“a:b::cd:“,分別表示程序支持的命令行短選項有-a、-b、-c、-d,冒號含義如下:
      1. 只有一個字符,不帶冒號——只表示選項, 如-c。
      2. 一個字符,後接一個冒號——表示選項後面帶一個參數,如-a 100。
      3. 一個字符,後接兩個冒號——表示選項後面帶一個可選參數,即參數可有可無, 如果帶參數,則選項與參數之間不能有空格,如-b123。
    • longopts:表示長選項結構體。其結構以及解釋如下:
    struct option { 
    const char *name;// 表示的是長選項名稱 
    int has_arg;// 表示選項後面是否攜帶參數。有3個值。
    // no_argument(或者是0),參數後面不跟參數值。
    // required_argument(或者是1),參數輸入格式爲:--參數 值 或者 --參數=值。
    // optional_argument(或者是2),參數輸入格式只能爲:--參數=值。
    int *flag;//用來決定函數的返回值。如果flag是null,則函數會返回與該項option匹配的val值,如果flag不是null,則函數返回0,並將flag指針參數指向與該項option匹配的val值。
    int val; //和flag聯合決定返回值 
    } 
    
    • longindex:longindex不是null的話則指向的變量將記錄longopts的下標值。

    • 返回值:

      1. 如果短選項找到,那麼將返回短選項對應的字符。
      2. 如果長選項找到,且flag爲null,返回val,flag不爲null,返回0。
      3. 如果發生錯誤,如:未識別選項或者必須加參數的選項丟失參數,返回“?”,如果在optstring中設置了第一個字符爲“:”,丟失參數返回“:”。
      4. 當縮寫長選項引起歧義時或者不需要的選項強加了參數,都會返回“?”。
      5. 返回-1表示選項處理全部結束。
      6. 如果在輸入的argv[]中包含了獨立的“--”字符串,解析到這裏返回-1,停止選項的解析。
  • 還有一些需要了解的全局變量:

    • optarg(指針):表示當前選項對應的參數值。
    • optind:表示的是下一個將被處理到的參數在argv中的下標值。
    • opterr:如果opterr = 0,遇到錯誤將不會輸出錯誤信息到標準輸出流。opterr在非0時,向屏幕輸出錯誤。
    • optopt:表示出錯或者未識別的選項。
  • 注意事項:

    • longopts的最後一個元素必須是全0填充,否則會報段錯誤
    • 短選項中每個選項都是唯一的。而長選項如果簡寫,也需要保持唯一性。
  • 下面是一個簡單的例子:

/* 程序運行參數結構體 */
struct InputArgs
{
  std::string user_id;
  std::string user_name;
  std::string pwd;

  void printArgs();

  bool checkArgs()
  {
    if (user_id.empty())
    {
      return false;
    }

    if (user_name.empty())
    {
      return false;
    }

    if (pwd.empty())
    {
      return false;
    }

    return true;
  }
};

InputArgs g_input_arg_info;

void InputArgs::printArgs(){
    printf("ARGS:  --= %s\n", userId.c_str());
    printf("        --userName = %s\n", user_name.c_str());
    printf("        --pwd = %s\n", pwd.c_str());
}

/* 參數解析 */
const char* short_options = "i:n:p:";
struct option long_options[] = {
    { "userId", required_argument, NULL, 'i' },
    { "userName", required_argument, NULL, 'n' },
    { "pwd", required_argument, NULL, 'p' },
    { 0, 0, 0, 0 }, 
};

void print_usage(){
    printf("DESCRIPTION\n");
    printf("  --userId, -i\n");
    printf("  --userName, -n\n");
    printf("  --pwd, -p\n");
}

void print_arg(int argc, char *argv[])
{
  for (int i = 0; i < argc; i++)
  {
    printf("%s\n", argv[i]);
  }
}

int parse_arg(int argc, char *argv[])
{
  print_arg(argc, argv);
  int c;
  std::string opt;
  while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) !=
         -1)
  {
    switch (c)
    {
    case 'i':
      opt = optarg;
      g_input_arg_info.user_id = opt;
      break;
    case 'n':
      opt = optarg;
      g_input_arg_info.user_name = opt;
      break;
    case 'p':
      opt = optarg;
      g_input_arg_info.pwd = opt;
      break;
    default:
      return -1;
    }
  }

  if (false == g_input_arg_info.checkArgs())
  {
    return -2;
  }

  return 0;
}

int main(int argc, char *argv[])
{
  if (0 != parse_arg(argc, argv))
  {
    print_usage();
    printf("parse input args failed!\n");
    return 1;
  }

  g_input_arg_info.printArgs();

  // do things here
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章