Linux下getopt()函數

from http://www.javashuo.com/article/p-efttehia-m.htmlhtml

最近在弄Linux C編程,本科的時候沒好好學啊,但願學弟學妹們引覺得鑑。linux

好了,雖然囉嗦了點,但確實是忠告。步入正題:shell

咱們的主角----getopt()函數。編程

英雄不問出處,getopt()函數的出處就是unistd.h頭文件(哈哈),寫代碼的時候千萬不要忘記把他老人家include上。數組

 

再來看一下這傢伙的原型(不是六耳獼猴):函數

int getopt(int argc,char * const argv[ ],const char * optstring);spa

前兩個參數你們不會陌生,沒錯,就是老大main函數的兩個參數!老大傳進來的參數天然要有人接着!命令行

第三個參數是個字符串,看名字,咱們能夠叫他選項字符串(後面會說明)code

返回值爲int類型,咱們都知道char類型是能夠轉換成int類型的,每一個字符都有他所對應的整型值,其實這個返回值返回的就是一個字符,什麼字符呢,叫選項字符(姑且這麼叫吧,後面會進一步說明)htm

 

簡單瞭解了出身和原型,下面咱們看看這傢伙到底有什麼本事吧!

(⊙o⊙)…在此以前還要介紹他的幾個兄弟~~~~呃呃呃

小弟一、extern char* optarg;

小弟二、extern int optind;

小弟三、extern int opterr;

小弟四、extern int optopt;

隊形排的不錯。小弟1是用來保存選項的參數的(先混個臉熟,後面有例子);小弟2用來記錄下一個檢索位置;小弟3表示的是是否將錯誤信息輸出到stderr,爲0時表示不輸出,小弟4表示不在選項字符串optstring中的選項(有點亂哈,後面會有例子)

開始逐漸解釋上面遺留的問題。

問題1:選項究竟是個什麼鬼?

在linux下你們都用過這樣一條指令吧:gcc helloworld.c -o helloworld.out; 這條指令中的-o就是命令行的選項,然後面的helloworld.out就是-o選項所攜帶的參數。固然熟悉shell指令的人都知道(雖然我並不熟悉),有些選項是不用帶參數的,而這樣不帶參數的選項能夠寫在一塊兒(這一點在後面的例子中會用到,但願理解),好比說有兩個選項-c和-d,這兩個選項都不帶參數(並且明顯是好基友),那麼他們是能夠寫在一塊兒,寫成-cd的。實際的例子:當咱們刪除一個文件夾時可使用指令 rm 目錄名 -rf,原本-r表示遞歸刪除,就是刪除文件夾中全部的東西,-f表示不提示就馬上刪除,他們兩個都不帶參數,這時他們就能夠寫在一塊兒。

問題2:選項字符串又是何方神聖?

仍是看個例子吧

"a:b:cd::e",這就是一個選項字符串。對應到命令行就是-a ,-b ,-c ,-d, -e 。冒號又是什麼呢? 冒號表示參數,一個冒號就表示這個選項後面必須帶有參數(沒有帶參數會報錯哦),可是這個參數能夠和選項連在一塊兒寫,也能夠用空格隔開,好比-a123 和-a   123(中間有空格) 都表示123是-a的參數;兩個冒號的就表示這個選項的參數是可選的,便可以有參數,也能夠沒有參數,但要注意有參數時,參數與選項之間不能有空格(有空格會報錯的哦),這一點和一個冒號時是有區別的。

好了,先給個代碼,而後再解釋吧。

 

#include <unistd.h> #include <stdio.h>
int main(int argc, char * argv[]) { int ch; printf("\n\n"); printf("optind:%d,opterr:%d\n",optind,opterr); printf("--------------------------\n"); while ((ch = getopt(argc, argv, "ab:c:de::")) != -1) { printf("optind: %d\n", optind); switch (ch) { case 'a': printf("HAVE option: -a\n\n"); break; case 'b': printf("HAVE option: -b\n"); printf("The argument of -b is %s\n\n", optarg); break; case 'c': printf("HAVE option: -c\n"); printf("The argument of -c is %s\n\n", optarg); break; case 'd': printf("HAVE option: -d\n"); break; case 'e': printf("HAVE option: -e\n"); printf("The argument of -e is %s\n\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; } } }

 

編譯後命令行執行:# ./main -b "qing er"

輸出結果爲:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

 

咱們能夠看到:optind和opterr的初始值都爲1,前面提到過opterr非零表示產生的錯誤要輸出到stderr上。那麼optind的初值爲何是1呢?

這就要涉及到main函數的那兩個參數了,argc表示參數的個數,argv[]表示每一個參數字符串,對於上面的輸出argc就爲3,argv[]分別爲: ./main 和 -b 和"qing er" ,實際上真正的參數是用第二個-b 開始,也就是argv[1],因此optind的初始值爲1;

當執行getopt()函數時,會依次掃描每個命令行參數(從下標1開始),第一個-b,是一個選項,並且這個選項在選項字符串optstring中有,咱們看到b後面有冒號,也就是b後面必須帶有參數,而"qing er"就是他的參數。因此這個命令行是符合要求的。至於執行後optind爲何是3,這是由於optind是下一次進行選項搜索的開始索引,也是說下一次getopt()函數要從argv[3]開始搜索。固然,這個例子argv[3]已經沒有了,此時getopt()函數就會返回-1。

再看一個輸入:

 ./main -b "qing er" -c1234

輸出結果爲:

optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er

optind: 4
HAVE option: -c
The argument of -c is 1234

 

對於這個過程會調用三次getopt()函數,和第一個輸入同樣,是找到選項-b和他的參數"qing er",這時optind的值爲3,也就意味着,下一次的getopt()要從argv[3]開始搜索,因此第二次調用getopt()函數,找到選項-c和他的參數1234(選項和參數是連在一塊兒的),因爲-c1234寫在一塊兒,因此他兩佔一塊兒佔用argv[3],因此下次搜索從argv[4]開始,而argv[4]爲空,這樣第三次調用getopt()函數就會返回-1,循環隨之結束。

 

接下來咱們看一個錯誤的命令行輸入: ./main -z 123

輸出爲:

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 2
Unknown option: z

其中./main: invalid option -- 'z'就是輸出到stderr的錯誤輸出。若是把opterr設置爲0那麼就不會有這條輸出。

 

在看一個錯誤的命令行輸入: ./main -zheng

 

optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 1
Unknown option: z
./main: invalid option -- 'h'
optind: 1
Unknown option: h
optind: 2
HAVE option: -e
The argument of -e is ng

前面提到過不帶參數的選項能夠寫在一塊兒,因此當getopt()找到-z的時候,發如今optstring 中沒有,這時候他就認爲h也是一個選項,也就是-h和-z寫在一塊兒了,依次類推,直到找到-e,發現optstring中有。

 

最後要說明一下,getopt()會改變argv[]中參數的順序。通過屢次getopt()後,argv[]中的選項和選項的參數會被放置在數組前面,而optind 會指向第一個非選項和參數的位置。看例子

 

#include <unistd.h> #include <stdio.h>
int main(int argc, char * argv[]) { int i; printf("--------------------------\n"); for(i=0;i<argc;i++) { printf("%s\n",argv[i]); } printf("--------------------------\n"); //int aflag=0, bflag=0, cflag=0;
    
       int ch; printf("\n\n"); printf("optind:%d,opterr:%d\n",optind,opterr); printf("--------------------------\n"); while ((ch = getopt(argc, argv, "ab:c:de::")) != -1) { printf("optind: %d\n", optind); switch (ch) { case 'a': printf("HAVE option: -a\n\n"); break; case 'b': printf("HAVE option: -b\n"); printf("The argument of -b is %s\n\n", optarg); break; case 'c': printf("HAVE option: -c\n"); printf("The argument of -c is %s\n\n", optarg); break; case 'd': printf("HAVE option: -d\n"); break; case 'e': printf("HAVE option: -e\n"); printf("The argument of -e is %s\n\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; } } printf("----------------------------\n"); printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]); printf("--------------------------\n"); for(i=0;i<argc;i++) { printf("%s\n",argv[i]); } printf("--------------------------\n"); }

命令行:./main zheng -b "qing er" han -c123 qing

 

輸出結果爲:

--------------------------
./main
zheng
-b
qing er
han
-c123
qing
--------------------------


optind:1,opterr:1
--------------------------
optind: 4
HAVE option: -b
The argument of -b is qing er

optind: 6
HAVE option: -c
The argument of -c is 123

----------------------------
optind=4,argv[4]=zheng
--------------------------
./main
-b
qing er
-c123
zheng
han
qing
--------------------------

 

能夠看到最開始argv[]內容爲:

./main
zheng
-b
qing er
han
-c123
qing

 

在執行了屢次getopt後變成了

./main
-b
qing er
-c123
zheng
han
qing

咱們看到,被getopt挑出的選項和對應的參數都按順序放在了數組的前面,而那些既不是選項又不是參數的會按順序放在後面。而此時optind爲4,即指向第一個非選項也非選項的參數,zheng

相關文章
相關標籤/搜索