在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,冒號含義如下:- 只有一個字符,不帶冒號——只表示選項, 如-c。
- 一個字符,後接一個冒號——表示選項後面帶一個參數,如-a 100。
- 一個字符,後接兩個冒號——表示選項後面帶一個可選參數,即參數可有可無, 如果帶參數,則選項與參數之間不能有空格,如-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的下標值。
-
返回值:
- 如果短選項找到,那麼將返回短選項對應的字符。
- 如果長選項找到,且flag爲null,返回val,flag不爲null,返回0。
- 如果發生錯誤,如:未識別選項或者必須加參數的選項丟失參數,返回“?”,如果在optstring中設置了第一個字符爲“:”,丟失參數返回“:”。
- 當縮寫長選項引起歧義時或者不需要的選項強加了參數,都會返回“?”。
- 返回-1表示選項處理全部結束。
- 如果在輸入的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
}