天天看點

Linux下getopt()函數的簡單使用

最近在弄Linux C程式設計,大學的時候沒好好學啊,希望學弟學妹們引以為鑒。

好了,雖然啰嗦了點,但确實是忠告。步入正題:

我們的主角----getopt()函數。

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

再來看一下這家夥的原型(不是六耳猕猴):

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

前兩個參數大家不會陌生,沒錯,就是老大main函數的兩個參數!老大傳進來的參數自然要有人接着!

第三個參數是個字元串,看名字,我們可以叫他選項字元串(後面會說明)

傳回值為int類型,我們都知道char類型是可以轉換成int類型的,每個字元都有他所對應的整型值,其實這個傳回值傳回的就是一個字元,什麼字元呢,叫選項字元(姑且這麼叫吧,後面會進一步說明)

簡單了解了出身和原型,下面我們看看這家夥到底有什麼本事吧!

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

小弟1、extern char* optarg;

小弟2、extern int optind;

小弟3、extern int opterr;

小弟4、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的參數;兩個冒号的就表示這個選項的參數是可選的,即可以有參數,也可以沒有參數,但要注意有參數時,參數與選項之間不能有空格(有空格會報錯的哦),這一點和一個冒号時是有差別的。

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

編譯後指令行執行:# ./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: 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

輸出為:

./main: invalid option -- 'z'

optind: 2

Unknown option: z

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

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

optind: 1

./main: invalid option -- 'h'

Unknown option: h

HAVE option: -e

The argument of -e is ng

前面提到過不帶參數的選項可以寫在一起,是以當getopt()找到-z的時候,發現在optstring 中沒有,這時候他就認為h也是一個選項,也就是-h和-z寫在一起了,依次類推,直到找到-e,發現optstring中有。

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

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

./main

zheng

-b

qing er

han

-c123

qing

optind: 6

The argument of -c is 123

----------------------------

optind=4,argv[4]=zheng

可以看到最開始argv[]内容為:

在執行了多次getopt後變成了

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

花了40多分鐘整理,希望能夠給需要的人帶來幫助。

很多時候我都在尋思,為啥要花時間整理,明明已經非常忙碌了,有這點時間休息一下多好,多惬意?

我總結的原因有一下幾個:

1、總結時會注意到之前沒有關注的問題,可以加深對問題的了解。

2、友善以後忘記的時候查閱

3、與廣大朋友們分享,想想我們從哪些大牛的部落格裡得到的太多了。我們應當向那些大神學習。把自己學到的分享出來,幫助其他人(雖然我很渣,但是三人行必有我師,應該還是會幫到些人吧)。

共勉!努力!

最後給大家介紹一個寫的更加全面的文章:http://blog.csdn.net/huangxiaohu_coder/article/details/7475156

繼續閱讀