在實際編程當中,自己編寫代碼處理命令行參數是比較麻煩且易出錯的。一般我們會直接使用getopt()
和getopt_long()
函數,下文將介紹具體的使用方法。
getopt()
getopt()
用于處理”單字母“選項,如-a
, -t
等。函數聲明如下:
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
參數說明
對于前兩個參數argc
和grgv[]
,一般直接使用main()
傳遞進來的數值。用過C語言的同學應該比較熟悉,簡單復習一下。
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char const *argv[])
{
//在C99標準推出之前,變量不能在for()聲明,為了兼容性,這里提前聲明"i"
int i;
printf("argc = %d\n", argc);
if (argc > 1)
{
for (i = 0; i < argc; ++i)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
}
return 0;
}
argc
: argument count, 記錄了命令行參數的個數(包括命令本身)
argv
: argument vector, 記錄了命令行參數的具體內容
$ ./test 1 2 3
argc = 4
argv[0] = ./test
argv[1] = 1
argv[2] = 2
argv[3] = 3
optstring
: 作為getopt()
的第三個參數,用于規定合法選項(option)以及選項是否帶參數(argument)。一般為合法選項字母構成的字符串,如果字母后面帶上冒號:
就說明該選項必須有參數。如"ht:"
說明有兩個選項-h
和-t
且后者(-t
)必須帶有參數(如-t 60
)。
返回值
option character
: 一般情況下,getopt()
讀取到合法選項,就返回該選項(一個字母)。-1
:結束標志。
while ( (opt = getopt(argc, argv, "ab:") ) != -1) {...}
?
: 一般情況下,遇到非法選項或者參數缺失都會返回?
。如果需要區分這兩種錯誤,可以在optstring
的開頭加上:
,如:ht:
, 這樣參數缺失就返回:
,非法選項就返回?
。:
:在optstring
參數開頭第一個字符為:
時,遇到參數缺失返回:
。參考下方代碼(摘自Linux Programming by Example)可幫助理解
int oc; /* option character */
char *b_opt_arg;
while ((oc = getopt(argc, argv, ":ab:")) != -1) {
switch (oc) {
case 'a':
/* handle -a, set a flag, whatever */
break;
case 'b':
/* handle -b, get arg value from optarg */
b_opt_arg = optarg;
break;
case ':':
/* missing option argument 參數缺失*/
fprintf(stderr, "%s: option '-%c' requires an argument\n",
argv[0], optopt);
break;
case '?':
default:
/* invalid option 非法選項*/
fprintf(stderr, "%s: option '-%c' is invalid: ignored\n",
argv[0], optopt);
break;
}
}
相關變量
-
optind
(option index): 數組下標,指向下一個未處理的參數。通過例子(摘自stackoverflow)能更好理解:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char optStr[] = "ab";
int c;
while ((c = getopt(argc, argv, optStr)) != -1) {
printf("optind: %d\n", optind);
switch (c) {
case 'a':
printf("-a\n");
break;
case 'b':
printf("-b\n");
break;
case '?':
printf("error\n");
break;
}
}
return 0;
}
測試結果:
$ ./a.out -ab #例子1
optind: 1
-a
optind: 2
-b
$ ./a.out -a #例子2
optind: 2
-a
例子1:
#argv[]數據如下
argv[0]="./a.out"
argv[1]="-ab"
argv[2]=0
從optind
=1開始,處理完a
,optind
指向b
所在位置,其實還是1;處理完b,指向下一個選項,即2
例子2:
#argv[]數據如下
argv[0]="./a.out"
argv[1]="-a"
argv[2]=0
從optind
=1開始,處理完a,指向下一個選項,即2
-
optarg
: 如果合法選項帶有參數,那么對應的參數,賦值給optarg
getopt_long()
根據函數名就可以知道getopt_long()
用于處理長選項,如-help
。函數聲明如下:
#include <getopt.h>
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex);
參數說明
前三個選項和getopt()
完全相同,在此不再贅述。
-
longopts數組
: 用于規定合法長選項以及長選項是否帶參數(argument)。涉及到的option結構體
聲明如下
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
-
name
: 長選項的名稱 -
has_arg
: 參數情況
符號常量 | 數值 | Meaning |
---|---|---|
no_argument |
0 |
無參數 |
required_argument |
1 |
有參數 |
optional_argument |
2 |
參數可選 |
考慮到“可讀性”,一般使用“符號常量”
-
int *flag
: 如果flag
為NULL
,getup_long()
返回val
的值; 如果不是NULL
,val
的值賦給flag
指針指向的內容,同時getopt_long()
返回 0 -
int val
:flag
為NULL
,val
作為getopt_long()
的返回值;如果flag
不為NULL
,val
賦值給flag
指針所指內容;
int *flag | return value |
---|---|
NULL |
val |
&name (<— val ) |
0 |
通過例子(摘自webbench)可加深理解
static const struct option long_options[]=
{
{"force",no_argument,&force,1}, //-force 參數三(flag)不為NULL,force=1,getopt_long()返回0
{"reload",no_argument,&force_reload,1},
{"time",required_argument,NULL,'t'},
{"help",no_argument,NULL,'?'}, //-help 第三個參數(flag)為NULL,直接返回 "?"
{"http09",no_argument,NULL,'9'},
{"http10",no_argument,NULL,'1'},
{"http11",no_argument,NULL,'2'},
{"get",no_argument,&method,METHOD_GET},
{"head",no_argument,&method,METHOD_HEAD},
{"options",no_argument,&method,METHOD_OPTIONS},
{"trace",no_argument,&method,METHOD_TRACE},
{"version",no_argument,NULL,'V'},
{"proxy",required_argument,NULL,'p'},
{"clients",required_argument,NULL,'c'},
{NULL,0,NULL,0} //最后一個元素應該全為0
};
int main(int argc, char *argv[])
{
int options_index=0;
...
while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
{
...
}
}
注意:
longopts數組
的最后一個元素應該全為0.
-
longindex
: 一般設置為NULL
; 如果不為NUll
, 指向每次找到的長選項在longopts
的位置,可以通過該值(即索引)找到當前長選項的具體信息。
希望本文能幫助大家更好地理解getopt()
和getopt_long()
。更多的相關用法可以參考Linux Programming by Example: The Fundamentals