函数 —— 分析命令行参数 getopt() getopt_long() getopt_long_only()
getopt()函數
1、功能描述;
?????getopt - parse command options (enhanced) ?(解析命令選型(增強))
2、表頭文件:
? ??? ?#include<unistd.h>
3、定義函數:
????? ? int getopt(int argc, char * const argv[] ,const char * optstring);
?????????extern char *optarg;
? ? ? ? ?extern int optind, opterr, optopt;
4、optstring中的內容的意義:
????????字符串參數optstring --?optstring是由選項Option字母組成的字符串。
????? ? 例如:getopt(argc,argv,"ab:c:de::")
????? ? 1、單個字符,[a] [b] [c] [d] [e], 表示選項;
????? ? 2、單個字符后接一個冒號 ':' , [b:] ?[c:] ,表示該選項后必須跟一個參數。
????????????????????????????????參數緊跟在選項后或或者以空格隔開,參數的指針賦值給optarg;
????? ? 3、單個字符后有兩個冒號 '::' ,[ e:: ],表示該選項后可以跟一個參數,也可以不跟。
????????????????????????? ??如果跟一個參數,參數必須緊跟在選項后不能以空格隔開,參數指針賦值給optarg(未賦值 optarg = NULL);
5、getopt設置的全局變量:
????? ? optarg——指向當先選項的參數(如果有)的指針;(當匹配一個選項后,如果該選項帶選項參數,則optarg指向選項參數字符串;若該選項不帶選項參數,則optarg為NULL;若該選項的選項參數為可選時,optarg為NULL表明無選項參數,optarg不為NULL時則指向選項參數字符串。)
????? ? optind——再次調用getopt()時的下一個argv指針的索引;(一個待處理元素在argv中的索引值。即下一次調用getopt的時候,從optind存儲的位置處開始掃描選項。當getopt()返回-1后,optind是argv中第一個Operands的索引值。optind的初始值為1。)
????? ? opteer——opterr的值非0時,在getopt()遇到無法識別的選項,或者某個選項丟失選項參數的時候,getopt()會打印錯誤信息到標準錯誤輸出。opterr值為0時,則不打印錯誤信息。opterr默認為1。
? ? ? ? optopt——最后一個未知選項。(在上述兩種錯誤之一發生時,一般情況下getopt()會返回'?',并且將optopt賦值為發生錯誤的選項。?)
來看個實例,我們定義字符串參數為const char *optstring = "a:b:c::d";
從前面的知識點,我們很容易得出結論:
? ? ? ? 選項a,b是必須要加一個參數的;?? ? ? ?
? ? ? ? 選項c的選項參數是可選的,即如果提供選項c的選項參數的話,那么選項參數必須緊跟選項c之后,不能以空格隔開;
? ? ? ? 選項d是不需要選項參數的 ?選項b,c需要選項參數,而選項e的選項參數是可選的,
深入理解 ? optarg ? 全局變量:?
#include<stdio.h> #include<unistd.h> int main(int argc ,char **argv) {int opt;const char *optstring = "a:b:c::d";while((opt = getopt(argc, argv, optstring)) != -1){printf("opt = %c\n",opt);printf("optarg = %s\n",optarg);}return 0; }執行結果分析如下:
//選項必須匹配參數時,但未匹配參數時候,getopt返回?字符, optarg為NULL [root@localhost getopt]# ./a.out -a ./a.out: option requires an argument -- 'a' opt = ? optarg = (null) //選項必須匹配參數時,且匹配參數后,getopt返回選項參數字符,optarg指向選項參數字符串 [root@localhost getopt]# ./a.out -a aa opt = a optarg = aa //選項匹配參數可選時,但未匹配參數時候,getopt返回選項參數字符,optarg為NULL [root@localhost getopt]# ./a.out -c opt = c optarg = (null) //選項匹配參數可選時,匹配好參數但是未緊跟在選項后,getopt返回該選項字符,optarg為NULL [root@localhost getopt]# ./a.out -c cc opt = c optarg = (null) //選項匹配參數可選時,匹配參數 并且緊跟在選項參數后,getopt返回該選項字符,optarg指向選項參數字符串 [root@localhost getopt]# ./a.out -ccc opt = c optarg = cc //選項不需要匹配參數時,getopt返回該選項字符,optarg為NULL [root@localhost getopt]# ./a.out -d opt = d optarg = (null) //選項未定義時候,getopt返回?字符,optarg為NULL [root@localhost getopt]# ./a.out -A ./a.out: invalid option -- 'A' opt = ? optarg = (null)深入理解 ? optind? ?全局變量:
int main(int argc ,char **argv) {int opt;const char *optstring = "a:b:c::d";while((opt = getopt(argc, argv, optstring)) != -1){printf("opt = %c\n",opt);printf("optind = %d\n",optind);printf("argv[optind - 1] = %s\n",argv[optind - 1]);}return 0; }執行結果分析如下: //表示下一次調用getopt時候,下一個argv值的索引;即下一次調用getopt時,從optind存儲的位置處開始掃描 [root@localhost getopt]# ./a.out -a aa -b bb -c cc -d opt = a optind = 3 argv[optind - 1] = aa opt = b optind = 5 argv[optind - 1] = bb opt = c optind = 6 argv[optind - 1] = -c opt = d optind = 8 argv[optind - 1] = -d //并沒有先掃描AA getopt()返回-1后,optind是argv中第一個operands的索引值。optind的初始值為1. [root@localhost getopt]# ./a.out -a aa AA -b bb -cCC -d opt = a optind = 3 argv[optind - 1] = aa opt = b optind = 6 argv[optind - 1] = bb opt = c optind = 7 argv[optind - 1] = -cCC opt = d optind = 8 argv[optind - 1] = -d 深入理解? ?opterr? ?全局變量:int main(int argc ,char **argv) {int opt;printf("opterr = %d\n",opterr);const char *optstring = "a:b:c::d";while((opt = getopt(argc, argv, optstring)) != -1){}return 0; }執行結果分析如下: //opterr默認值為1 當getopt遇到無法識別的選項 或者某個選項丟失選項參數的時候,getopt會打印錯信息到標準錯誤輸出 [root@localhost getopt]# ./a.out -A opterr = 1 ./a.out: invalid option -- 'A' [root@localhost getopt]# ./a.out -a opterr = 1 ./a.out: option requires an argument -- 'a'
但是當設置opterr為0時,則不會打印這些信息(在getopt函數之前加入代碼? opterr = 0; 即可)。
深入理解? ?optopt? ?全局變量:
綜合描述:
執行結果分析如下:
[root@localhost getopt]# ./a.out -A -d -cCC -a aa -b ./a.out: invalid option -- 'A' opt = ? optarg = (null) optind = 2 argv[optind - 1] = -A optopt = Aopt = d optarg = (null) optind = 3 argv[optind - 1] = -d optopt = Aopt = c optarg = CC optind = 4 argv[optind - 1] = -cCC optopt = Aopt = a optarg = aa optind = 6 argv[optind - 1] = aa optopt = A./a.out: option requires an argument -- 'b' opt = ? optarg = (null) optind = 7 argv[optind - 1] = -b optopt = b6、getopt()使用時候,經常會犯的錯誤:? ? ? ??
無法識別的選項(Invalid option)?和丟失選項參數(Missing option argument)
通常情況下,getopt()在發現這兩個錯誤時,會打印相應的錯誤信息,并且返回字符"?" (示例見上方 深入理解 ? optarg ? 全局變量)。例如,遇見無法識別的選項時會打印"invalid option"(深入理解 ? optarg ? 全局變量? ?-》?# ./a.out -A),發現丟失參數時打印"option requires an argument"深入理解 ? optarg ? 全局變量? ?-》?# ./a.out -a。但是當設置opterr為0時,則不會打印這些信息,因此為了便于發現錯誤,默認情況下,opterr都是非零值(示例見上方深入理解? ?optopt? ?全局變量)。
如果你想親自處理這兩種錯誤的話,應該怎么做呢? 首先你要知道什么時候發生的錯誤是無法識別的選項,什么時候發生的錯誤是丟失選項參數。如果像上面描述的那樣,都是返回字符"?"的話,肯定是無法分辨出的。有什么辦法嗎? 有! getopt()允許我們設置optstring的首字符為冒號":",在這種情況下,當發生無法識別的選項錯誤時getopt()返回字符"?",當發生丟失選項參數錯誤時返回字符":"。這樣我們就可以很輕松地分辨出錯誤類型了,不過代價是getopt()不會再打印錯誤信息了,一切事物都由我們自己來處理了。
分辨錯誤類型(無法識別的選項、丟失選項參數), 并打印錯誤信息:
int main(int argc ,char **argv) {int opt;const char *optstring = ":a:b:c::d"; //注意在字符串參數最前面有一個冒號while((opt = getopt(argc, argv, optstring)) != -1){printf("opt = %c\n",opt); //可以根據opt返回的字符的類型 判斷是什么錯誤類型printf("optarg = %s\n",optarg);printf("optopt = %c\n",optopt); //發生錯誤的選項 賦值給 optoptif(ch == 63) //? 無法識別的選項的判斷{printf("./a.out: invalid option -- '%c'\n\n",optopt);}if(ch == 58) //: 丟失選項參數的判斷{printf("./a.out: option requires an argument -- '%c'\n",optopt);}}return 0; }結果分析:
[root@localhost getopt]# ./a.out -a -A opt = a optarg = -A optopt = [root@localhost getopt]# ./a.out -A -a opt = ? optarg = (null) optopt = A ./a.out: invalid option -- 'A'opt = : optarg = (null) optopt = a ./a.out: option requires an argument -- 'a'7、getopt()參數是如何操作命令行參數的(如何掃描參數的):
command name:?是程序的名字; option: 操作的選項; option argument:選型 option所需要的信息: operands: 操作對象 又稱為nonoption argument。 getopt()的默認模式掃描模式是這樣的:getopt()從左到右按順序掃描argv[1]到argv[argc-1],并將選項Option和選項參數Option argument按它們在命令行上出現的次序放到argv數組的左邊,而那些Operands則按它們出現的次序放在argv的后邊。也就是說,getopt()在默認掃描模式下,會重新排序argv數組。
來看個實例,假設我們調用getopt(argc, argv, "ab:c:de::");
從前面的知識點,我們很容易得出結論:選項a,d是不需要選項參數的,選項b,c需要選項參數,而選項e的選項參數是可選的,即如果提供選項e的選項參數的話,那么選項參數必須緊跟選項e之后,不能以空格隔開 #include <stdio.h> #include <stdlib.h> #include <getopt.h> static int cnt = 1; static void print(int optc,int argc,char *argv[],int optind) {int i;printf("%02d: optc - '%c',argv:",cnt++,optc);for(i=0;i<argc;i++){printf("%s ",argv[i]);}printf("----- optind = %d\n",optind); } int main(int argc ,char *argv[]) {int optc;print('0',argc,argv,optind);//while ((optc = getopt(argc, argv, ":ab:c:de::")) != -1) {//while ((optc = getopt(argc, argv, "+ab:c:de::")) != -1) {//while ((optc = getopt(argc, argv, "-ab:c:de::")) != -1) {while ((optc = getopt(argc, argv, "-:ab:c:de::")) != -1) { //既可以不排序 也可以判斷是那種錯誤形式print(optc, argc, argv, optind);switch (optc) {default:break;}}print('0',argc,argv,optind);return 0; } 運行情況如下:
當然在真實情況下,一個程序很少需要這么多的Operands,這里只是為了更清楚地演示getopt()是如何掃描命令行參數的。
掃描過程中,要時刻銘記optind是下一個待處理元素在argv中的索引,當遇到Operands的時候則跳過,optind數值增加跳過的Operands個數。好,現在我們根據這些規則,詳細分析下剛剛程序的掃描過程:
第一行:即getopt()掃描重排序之前,可以看到optind的值默認被初始化為1。
第二行:getopt()首先從operand1開始掃描,發現operand1是Operands,則跳過,optind增加1等于2指向-a,繼續掃描。掃描到-a時發現是有效選項,則optind增加1等于3指向operand2,然后返回選項a。
第三行:在繼續掃描前,getopt()重新排序argv數組,將“-a”和“operand1”的位置互換。繼續掃描,發現operand2是Operands,跳過,optind增加1等于4指向-b,繼續掃描。發現-b是有效選項,因為選項b需要參數,因此把barg的首地址賦給optarg,optind增加2等于6指向operand3,返回選項b。
第四行:在繼續掃描前,getopt()重新排序argv數組,將“-b barg”和“operand1 operand2”的位置互換。繼續掃描,發現operand3是Operands,跳過,optind增加1等于7指向-c,繼續掃描。掃描到-c是發現是有效的選項,因為選項c跟選項b一樣,都需要參數,因此處理過程是一樣的,把carg的首地址賦給optarg,optind增加2等于9指向operand4,返回選項c。
第五行:在繼續掃描前,getopt()重新排序argv數組,將“-c carg”和“operand1 operand2 operand3”的位置互換。繼續掃描,發現operand4是Operands,跳過,optind增加1等于10指向-d,繼續掃描。掃描到-d時發現是有效選項,因為選項d不需要參數,因此直接optind增加1等于11指向operand5,返回選項d。
第六行:在繼續掃描前,getopt()重新排序argv數組,將“-d”和“operand1 operand2 operand3 operand4”的位置互換。繼續掃描,發現operand5是Operands,跳過,optind增加1等于12指向operand6,繼續掃描。掃描到operand6時發現依然是Operands,跳過,optind增加1等于13指向-e,繼續掃描。掃描到-e時發現是有效選項,因為后面的operand7與-e之間有間隔,因此這里選項e沒有參數。optind增加1等于14指向operand7,返回選項e。
第七行:在繼續掃描前,getopt()重新排序argv數組,將“-e”和“operand1 operand2 operand3 operand4 operand5 operand6”的位置互換。繼續掃描,發現operand7是Operands,跳過,optind增加1等于15指向argv[argc],即NULL。至此掃描完畢,getopt()重新設置optind為8,是其指向第一個Operands,即operand1,最后返回-1停止掃描。
--------------------------------------------------------------------------------------------------------------------------------------------
但是有的時候,你可能希望你的程序接收的參數中Operands必須放在最后,也就是遇到第一個Operands就立即停止參數掃描。
例如:遇到operand1時候就停止掃描
可以通過將optstring的首字符設置為‘+’來改變getopt()的掃描模式。我們可以修改前面的程序為getopt(argc, argv, "+ab:c:de::");
可以看到,這種掃描模式下,的確遇到第一個Operands時就立即停止掃描,忽略后續所有命令行參數,也不會進行重排序操作。
--------------------------------------------------------------------------------------------------------------------------------------------
此外,還有最后一種掃描模式是通過將optstring首字符設置為“-”來實現的。我們將程序改為getopt(argc, argv, "-ab:c:de::");先來看下運行結果:可以看到在這種模式下,getopt()會按順序掃描整個命令行參數,遇到有效選項時會正常處理,而遇到Operands時卻是這樣處理的:返回1,optarg賦值為Operands的首地址。
b, c字符后只識別一個,Operands;a,d,e后跟幾個識別幾個;
至此,我們就介紹完了getopt()的所有掃描模式。需要補充的兩點是:
1. 在后兩種掃描模式的情況下,如果還需要自己來區分無效選項和丟失選項參數這兩種錯誤的話,那么應該將optstring的第二個字符設置為字符‘:’。
2. 不管在哪種掃描模式下,當遇到字符串“--”時都會停止掃描,后續的命令行參數當作Operands來處理。所以如何刪除文件名以‘-’起始的文件?例如當前目錄下有個文件的名字是“-foo”,如何刪除呢? 有兩種辦法:1. rm ./-foo 2. rm -- -foo
getopt_long()函數
1、功能描述;
????getopt, getopt_long, getopt_long_only, optarg, optind, opterr, optopt - Parse command-line options
2、表頭文件:
? ??? #include <getopt.h>
3、定義函數:
????? ?int getopt_long(int argc, char * const argv[],
? ? ? ? ? ? ? ? ? const char *optstring,
? ? ? ? ? ? ? ? ? const struct option *longopts, int *longindex);
4、函數中的內容的意義:
????????字符串參數optstring --?optstring是由選項Option字母組成的字符串。
負責處理短參數。也稱為選項指定符字符串,該字符串告訴getopt哪些選項可用,以及它們是否有關聯值。optstring只是一個字符列表。
????? ? 例如:getopt(argc,argv,"ab:c:de::")
????? ? 1、單個字符,[a] [b] [c] [d] [e], 表示選項;
????? ? 2、單個字符后接一個冒號 ':'?, [b:] ?[c:] ,表示該選項后必須跟一個參數。
????????????????????????????????參數緊跟在選項后或或者以空格隔開,參數的指針賦值給optarg;
????? ? 3、單個字符后有兩個冒號 '::'?,[ e:: ],表示該選項后可以跟一個參數,也可以不跟。
????????????????????????? ??如果跟一個參數,參數必須緊跟在選項后不能以空格隔開,參數指針賦值給optarg(未賦值 optarg = NULL);
? ? ? ?參數longopts,其實是一個結構的示例:
負責處理長參數。指向一個由option結構體組成的數組,那個數組的每一個元素都指明了一個長參數(形如”–name”的參數)名稱和性質
????? ? ?struct option {
? ? ? ? ? ? ? ?const char *name; //name 表示是長參數名
? ? ? ? ? ? ? ?int? ? ? ? ?has_arg;? ?//has_arg 有三個值?
? ? ? ? ? ? ? ?int? ? ? ? *flag;//用來決定,getopt_long()的返回值到底是什么。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//如果flag是null(通常情況),則函數會返回與該項option匹配的val值;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //如果flag不是null,則將val值寫入flag所指向的內存,并且返回值設置為0;
? ? ? ? ? ? ? ?int? ? ? ? ?val;//和flag 聯合決定返回值
? ? ? ? ? ?};
? ? ? ? 參數flag,表示當前長參數在longopts中的索引值。
? ? ? ?//has_arg有3個值,
? ? ? ? ? ?????????????????//no_argument(或者是0),表示該參數后面不跟參數值
????????????????????? ? ? ? ?// optional_argument(或者是2),表示該參數后面可以跟,也可以不跟參數值。參數輸入格式只能為:--參數=值。 參數longindex: 如果longindex非空,它指向的變量將記錄當前找到參數符合longopts里的第幾個元素的描述,即是longopts的下標值。
5、示例:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <getopt.h>int main(int argc, char **argv) {int opt;int digit_optind = 0;int option_index = 0;char *optstring = "a:b:c:d";static struct option long_options[] = {{"reqarg", required_argument, NULL, 'r'},{"noarg", no_argument, NULL, 'n'},{"optarg", optional_argument, NULL, 'o'},{0, 0, 0, 0}};while ( (opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1){printf("opt = %c\n", opt);printf("optarg = %s\n", optarg);printf("optind = %d\n", optind);printf("argv[optind - 1] = %s\n", argv[optind - 1]);printf("option_index = %d\n\n", option_index);}return 0; }執行結果分析:
[root@localhost getopt]# ./a.out --optarg=sd --reqarg=asd --noarg opt = o optarg = sd optind = 2 argv[optind - 1] = --optarg=sd option_index = 2opt = r optarg = asd optind = 3 argv[optind - 1] = --reqarg=asd option_index = 0opt = n optarg = (null) optind = 4 argv[optind - 1] = --noarg option_index = 1 最后說說getopt_long_only函數,它與getopt_long函數使用相同的參數表,在功能上基本一致,只是getopt_long只將--name當作長參數,但getopt_long_only會將--name和-name兩種選項都當作長參數來匹配。在getopt_long在遇到-name時,會拆解成-n -a -m -e到optstring中進行匹配,而getopt_long_only只在-name不能在longopts中匹配時才將其拆解成-n -a -m -e這樣的參數到optstring中進行匹配。參考鏈接:https://blog.csdn.net/cashey1991/article/details/7942809
? ? ? ? ? ? ? ? ?https://blog.csdn.net/astrotycoon/article/details/46047449
總結
以上是生活随笔為你收集整理的函数 —— 分析命令行参数 getopt() getopt_long() getopt_long_only()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql —— C语言链接mysql数
- 下一篇: MODE —— 输出一个高度和宽度固定的