#include <unistd.h> int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt; #include <getopt.h> int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
glibc的特征測試宏要求(Feature Test Macro Requirements)(參見 feature_test_macros(7)):
getopt():
_POSIX_C_SOURCE >= 2 || _XOPEN_SOURCE || _POSIX_SOURCE
getopt_long()、
getopt_long_only():
_GNU_SOURCE
變量 optind 是 argv 中下一個要處理的元素的下標。系統將其初始化為1。調用者可以將其重置為1(譯注:此處當為筆誤,下文"備注"一節說是"將其重置為0",而且實際上,將其重置為0才能達到重新初始化getopt()的目的),以重新掃描同一個 argv 或重新掃描新的參數數組。
若 getopt() 找到另一個選項字符,則它返回那個字符,並更新外部變量optind、靜態變量nextchar,以期下次調用 getopt() 時,可以繼續掃描後續選項字符、argv元素。
若不再有選項字符串,則 getopt() 返回-1。此時,optind是第一個非選項argv元素的下標。
optstring 是包含有效選項的字符串。若這樣的字符後接一個冒號,則選項要求一個參數。因此, getopt() 設置一個指向同一個argv元素的後續文本的指針,或指向 下一个argv元素的指針,而 optarg 存儲了該元素(譯注:若選項與選項參數間有空白符時,則發生第一種情況;否則,發生第二種情況)。兩個冒號表示選項需要一個可選參數;若當前argv元素尚有文本(譯注:指當前argv元素在選項字符之後尚有字符)(譬如:其與選項名稱同名,如"-oarg"),則它由optarg返回,否則將optarg設置為0。這是一個GNU擴展。若 optstring 包含後接分號的 W ,則 -W foo 等價于長選項 --foo。 (POSIX.2為實現的擴展保留 -W 選項。)這種行為屬于GNU擴展,在glibc 2之前的庫中不可用。
getopt() 默認會改變其所掃描到的argv元素的次序,以期最終所有非選項元素都放置于最後。另外實現了兩種模式:若optstring的第一個字符為'+',或者設置了環境變量 POSIXLY_CORRECT ,則在處理選項時,一遇到非選項參數(譯注:這裡所說的"參數"是指命令行參數,也就是argv元素。下文為方便起見,當"參數"是指命令行參數時,將其譯為"argv元素"、"元素"或"選項")就停止;若optstring的第一個字符為'-',則將每個非選項argv元素當作字符編碼為1的選項元素來處理。(這用于編寫期望選項與其他argv元素以任意次序排列而又關注兩者的次序的程序。)"--"這個特殊參數強制忽略掃描模式並終止掃描選項。
若 getopt() 認不出某個選項字符,則它向stderr打印一條出錯信息,並在將該字符保存到optopt之後返回'?'。調用程序可通過將opterr設置為0來防止打印出錯信息。
若 getopt() 發現一個不包含于optstring之中的選項字符,或者發現一個遺漏了參數的選項,則它返回'?',並將外部變量optopt設置為實際的選項字符。若optstring的第一個字符(若存在上述任一可選的'+'或'-',則從其後計起)是冒號(':'),則 getopt() 返回':',而非'?',以指示遺漏了選項參數。若發現了錯誤,而optstring的第一個參數(譯注:計數方式同上)不是冒號,且外部變量opterr不為0(這是默認值),則 getopt() 打印一條出錯信息。
getopt_long()和getopt_long_only()
除了同時接受以兩個破折號(譯注:此處指西文破折號。在鍵盤上,它跟負號、減號、連字符指的是同一個鍵)開頭的長選項之外, getopt_long() 函數的操作跟 getopt() 類似。(若程序僅僅接受長選項,則應當將 optstring 設置為空字符串(""),而非NULL。)長選項可以使用縮寫,但要求該縮寫是唯一的,或與某個已定義的選項一模一樣。長選項可以使用 --arg=param 或 --arg param 參數格式。
longopts 是一個指向 struct option 數組的第一個元素的指針。該結構體像如下所示那樣聲明于 <getopt.h> :
struct option { const char *name; int has_arg; int *flag; int val; };
各個成員的含義如下:
必須要以0來填充數組的最後一個元素。
若longindex不為NULL,則它指向一個值為與 longopts 相應的長選項的下標值的變量。
getopt_long_only() 跟 getopt_long() 類似,但'-'和"--"都可以作為長選項標識。若以'-'(而非"--")開頭的選項沒有與之相匹配的長選項,但有與之相匹配的短選項,則將其看作短選項。
當 getopt_long() 和 getopt_long_only() 識別出短選項時,也會返回選項字符。對于長選項,若flag為NULL,則它們返回val;否則,返回0。對于 getopt() 而言,出錯跟返回-1是一樣的(譯注:言下之意,即是不會出錯,返回-1僅僅表示分析完所有命令行選項)。另外,若選項無效或選項缺失參數,則返回'?'。
在 optstring 中使用'+'和'-'是一種GNU擴展。
對于一些較舊的實現, getopt() 被聲明于 <stdio.h>。 SUSv1(譯注:Single UNIX Specification version 1,單一UNIX規範第1版)允許將其聲明于 <unistd.h> 或 <stdio.h>。 POSIX.1-2001指出為此而使用 <stdio.h> 是一種過時的做法。POSIX.1-2001不允許將其聲明于 <stdio.h>。
#include <unistd.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { int flags, opt; int nsecs, tfnd; nsecs = 0; tfnd = 0; flags = 0; while ((opt = getopt(argc, argv, "nt:")) != -1) { switch (opt) { case 'n': flags = 1; break; case 't': nsecs = atoi(optarg); tfnd = 1; break; default: /* '?' */ fprintf(stderr, "用法:%s [-t nsecs] [-n] name\n", argv[0]); exit(EXIT_FAILURE); } } printf("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind); if (optind >= argc) { fprintf(stderr, "選項之後應當有參數\n"); exit(EXIT_FAILURE); } printf("name參數 = %s\n", argv[optind]); /* 省略其他代碼 */ exit(EXIT_SUCCESS); }
以下實例程序通過 getopt_long() 的大量特性來闡明其用法。
#include <stdio.h> /* 為了支持printf */ #include <stdlib.h> /* 為了支持exit */ #include <getopt.h> int main(int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 1, 0, 'c'}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "abc:d:012", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("選項%s", long_options[option_index].name); if (optarg) printf("帶有參數%s", optarg); printf("\n"); break; case '0': case '1': case '2': if (digit_optind != 0 && digit_optind != this_option_optind) printf("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf("選項%c\n", c); break; case 'a': printf("選項a\n"); break; case 'b': printf("選項b\n"); break; case 'c': printf("選項c,其參數為'%s'\n", optarg); break; case 'd': printf("選項d,其參數為'%s'\n", optarg); break; case '?': break; default: printf("?? getopt所返回的字符編碼為0%o ??\n", c); } } if (optind < argc) { printf("非選項argv元素:"); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } exit(EXIT_SUCCESS); }
1. getopt()
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <getopt.h> void get_opt(int argc, char *const *argv, const char *optstring); int main(int argc, char **argv) { int i; const char optstring[2][8]= { /* 一遇到非選項參數就停止,並返回'?' */ "+ab:c::", /* 將每個非選項argv元素當作字符編碼為1的選項來處理,並返回':' */ "-:ab:c::", }; for(i=0; i<2; i++) { printf("--------- %c模式 ---------\n", optstring[i][0]); optind=0; /* 重新初始化getopt() */ get_opt(argc, argv, optstring[i]); } exit(EXIT_SUCCESS); } void get_opt(int argc, char * const *argv, const char *optstring) { int c; while (1) { optopt=-1; c=getopt(argc, argv, optstring); if (c == -1) break; switch (c) { case 'a': printf("選項a\n"); break; case 'b': printf("選項b,其參數為\"%s\"\n", optarg); break; case 'c': printf("選項c,", optarg); if(optarg != NULL) printf("其參數為\"%s\"\n", optarg); else printf("没有參數\n"); break; case '?': case ':': if(strchr(optstring, optopt) == NULL) printf("無效選項字符:%c\n", optopt); else printf("遺漏了參數的選項字符:%c\n", optopt); break; case 1: printf("非選項元素%s\n", optarg); } } if(optind < argc) { int i=1; printf("非選項元素:"); while(optind < argc) printf("\n%d. %s", i++, argv[optind++]); printf("\n"); } }
2. getopt_long
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <getopt.h> void get_opt(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longindex); int main(int argc, char **argv) { int i, longindex; int x=1; const char optstring[2][9]= { "aW;b:c::", "", }; struct option longopts[]= { {"again", no_argument, NULL, 'a'}, {"agn", no_argument, NULL, 'a'}, {"block-size", required_argument, NULL, 'b'}, {"counts", optional_argument, &x, 'c'}, {NULL, 0, NULL, 0 }, }; for(i=0; i<2; i++) { optind=0; printf("----------------------------------------------\n"); get_opt(argc, argv, optstring[i], longopts, &longindex); } exit(EXIT_SUCCESS); } void get_opt(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex) { int c; while (1) { c=getopt_long(argc, argv, optstring, longopts, longindex); if (c == -1) break; switch (c) { case 'a': printf("選項a\n"); break; case 'b': printf("選項b,其參數為\"%s\"\n", optarg); break; case 'c': printf("選項c,", optarg); if(optarg != NULL) printf("其參數為\"%s\"\n", optarg); else printf("没有參數\n"); break; case 0: printf("flag=%d, val=%d, &flag=%p, &val=%p\n", *(longopts[*longindex].flag), (longopts+*longindex)->val, longopts[*longindex].flag, &(longopts+*longindex)->val); case '?': /* 若選項無效或選項缺失參數,则会返回'?'。查找 出现此情况的确切原因的代码比较长,这里省略,由 optget*()自身去报告。*/ break; case 'W': /* 当optstring含有后接分号的'W'时,getopt*()会将"-W" 后的选项当作长选项,但它不能检测出该长选项是否有效。 如果你 * 想检测的话,唯有自己动手了。这里省略。 */ break; } } if(optind < argc) { int i=1; printf("非選項元素:"); while(optind < argc) printf("\n%d. %s", i++, argv[optind++]); printf("\n"); } }
3. getopt_long_only()
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <getopt.h> void get_opt(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longindex); int main(int argc, char **argv) { int i, longindex; const char optstring[2][9]= { "ab:c::", "", }; struct option longopts[]= { {"again", no_argument, NULL, 'a'}, {"block-size", required_argument, NULL, 'b'}, {"counts", required_argument, NULL, 'c'}, {"abc", no_argument, NULL, 'd'}, {NULL, 0, NULL, 0 }, }; for(i=0; i<2; i++) { optind=0; printf("----------------------------------------------\n"); get_opt(argc, argv, optstring[i], longopts, &longindex); } exit(EXIT_SUCCESS); } void get_opt(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex) { int c; while (1) { c=getopt_long_only(argc, argv, optstring, longopts, longindex); if (c == -1) break; switch (c) { case 'a': printf("選項a\n"); break; case 'b': printf("選項b,其參數為\"%s\"\n", optarg); break; case 'c': printf("選項c,", optarg); if(optarg != NULL) printf("其參數為\"%s\"\n", optarg); else printf("没有參數\n"); break; case 'd': printf("選項d,其參數為\"%s\"\n", optarg); break; case '?': opterr=0; /* 防止getopt()报告错误 */ printf("選項無效或選項缺失參數\n"); break; } } if(optind < argc) { int i=1; printf("非選項元素:"); while(optind < argc) printf("\n%d. %s", i++, argv[optind++]); printf("\n"); } }