linux下getopt函式的用法

森幾許發表於2014-08-04

getopt()函式用於命令列引數解析。先來看一下main函式的引數。

1,程式引數

   C語言編寫的linux程式執行時,是從main函式開始的。main函式的宣告如下:

        int main(int argc, char* argv[])

        或者

        int main(int argc, char** argv)

        其中,argc是程式引數的個數,argv是一個代表自身的字串陣列。

 

實驗:下面這個程式args.c對其引數進行檢查:

<span style="font-size:12px;">#include<stdio.h>
#include<stdlib.h>

int main(int argc, char* argv[])
{
	int arg;
	printf("The number of parameters: argc=%d\n",argc);
	for(arg=0;arg<argc;arg++)
	{
		printf("argv[%d] = %s\n",arg,argv[arg]);
	}
	exit(0);
}</span>

經過編譯後,執行

gcc -o args args.c 
./args -a -b host -chello -de -f world

結果如下:

The number of parameters: argc=8
argv[0] = ./args
argv[1] = -a
argv[2] = -b
argv[3] = host
argv[4] = -chello
argv[5] = -de
argv[6] = -f
argv[7] = world

        注:1)引數個數包括程式名本身;  2)argv是一個字串陣列;3)-de選項其實是-d和-e選項組合的,getopt可以識別這種情況的兩個選項。

2,getopt函式

 

#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);

以下全域性變數配合 getopt 函式。

extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;

         實際上,在命令列中,可以支援這樣命令輸入的資訊:
               選項:一個選項一般完成不同的功能的操作。
               引數(關聯值):在執行相應選項功能操作時輸入的資訊。
               -a:選項:表示所有。
               -h host_id: h 就是一個選項,但host_id 實際上是一個IP,也就是h 的引數。

      getopt函式將傳遞給main函式的argc和argv作為引數,同時接受一個選項指定符字串optstring,該字元告訴getopt哪些選項可用,以及它們是否有關聯值(引數)。optstring約定:
    (1)如果就是一個字元,表示某個選項。
    (2)如果一個字元後有1 個冒號,表示選項後面一定要跟一個引數。引數可以緊跟選項或者與選項相隔一個空格。
    (3)如果一個字元後有2 個冒號,表示選項後面可有有一個引數,也可以沒有引數,在選項後的引數一定不能跟它以空格間隔。

       例如getopt 函式第三個引數為以下值:
     “ab:c::d::”
      a 後面 沒有冒號,是一個選項。
      b 後面有冒號,其後的內容一定要有理解為引數。
      c 和d 雙冒號,其後的內容可以有,也可以沒有,但如果有,則這個引數一定堅挨著。
      因此如下:      

             ./getopt –a –b host –chello –d

       

        getopt每次先查詢‘-’後面的字元,再檢視該字元是否是optstring中的選項,以及是否帶有正確的引數。對於前面不帶‘-’的,且不是作為引數的字元或字串,則不予理會。

        具體getopt 怎麼來解釋我們的選項和引數。
        每成功執行一次,將返回當前的一個選項。迴圈呼叫getopt就可以依次得到每個選項。

            (1)如果選項有一個關聯值,則extern char *optarg指向這個值,否則為NULL;

            (2)如果選項處理完畢,getopt返回-1;

         (3)如果遇到一個無法識別的選項,getopt返回一個問號(?),並把它儲存到外部變數optopt中;並把有一個關聯值,則extern char *optarg指向這個值,否則為NULL;

         (4)如果一個選項要求有一個關聯值(例如例子中的-a),但使用者未提供這個值,getopt通常將返回一個問號;但如果

                   ./getopt_exp -a -b 'hi there' -chello world -de -f     (optstring為"a:b:c::de")

                          程式會將-b當成-a的關聯值。

                    如果我們將選項字串的第一個字元設定為冒號,那麼getopt將在使用者未提供值的情況下返回冒號,而不是?。

                  

                   extern char *optarg;      //如果當前選項後面一定要跟一個引數,且存在引數,則optarg指向該引數;否則為null

                   extern int optind;           //下一個要處理引數的索引
                   extern int optopt;          //用於儲存無法識別的選項

                   extern int opterr;           //opterr== 0,不將錯誤輸出的標準錯誤輸出裝置。 

 

<span style="font-size:12px;">#include<stdio.h>
#include<unistd.h>

int main(int argc, char* argv[])
{
	int opt,i;
	opterr=0;
	while((opt=getopt(argc,argv,"a:b:c::de"))!=-1)
	{
		switch(opt)
		{
		case 'a':
		printf("option=a,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		case 'b':
		printf("option=b,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		case 'c':
		printf("option=c,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		case 'd':
		printf("option=d,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		case 'e':
		printf("option=e,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		case '?':
		printf("opt=?,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",optarg,optind,optopt,opterr);
		break;
		default:
		printf("default,opt=%c,optarg=%s,optind=%d,optopt=%c,opterr=%d\n",opt,optarg,optind,optopt,opterr);
		break;
		}
		printf("opt=%c\n",opt);
		printf("argv[%d]=%s\n",optind,argv[optind]);
	}
	printf("\nopt=%d,optind=%d\n\n",opt,optind);
	for(;optind<argc;optind++)
		printf("argv[%d]= %s\n",optind,argv[optind]);
	printf("\n");
	for(i=1;i<argc;i++)
		printf("at the end ---- argv[%d]=%s\n",i,argv[i]);
	return 0;
}</span>


編譯:gcc -o getopt_exp getopt_exp.c;執行./getopt_exp -a here -b 'hi there' -chello -de come -f world後,結果為

option=a,optarg=here,optind=3,optopt=,opterr=0
opt=a
argv[3]=-b
option=b,optarg=hi there,optind=5,optopt=,opterr=0
opt=b
argv[5]=-chello
option=c,optarg=hello,optind=6,optopt=,opterr=0
opt=c
argv[6]=-de
option=d,optarg=(null),optind=6,optopt=,opterr=0
opt=d
argv[6]=-de
option=e,optarg=(null),optind=7,optopt=,opterr=0
opt=e
argv[7]=come
opt=?,optarg=(null),optind=9,optopt=f,opterr=0
opt=?
argv[9]=world

opt=-1,optind=8

argv[8]= come
argv[9]= world

at the end ---- argv[1]=-a
at the end ---- argv[2]=here
at the end ---- argv[3]=-b
at the end ---- argv[4]=hi there
at the end ---- argv[5]=-chello
at the end ---- argv[6]=-de
at the end ---- argv[7]=-f
at the end ---- argv[8]=come
at the end ---- argv[9]=world

 注:1)getopt能夠處理出現在程式引數中任意位置的選項。程式結束後,getopt實際上重組了argv陣列,把所有非選項引數集中在一起,從argv[optind]位置開始。如程式結果中的argv[8]。

	for(;optind<argc;optind++)
		printf("argv[%d]= %s\n",optind,argv[optind]);

2)opt,即 getopt函式的返回值,是一個選項,即一個字元,輸出時用%c,不能用%s,否則會出現Segmentation fault (core dumped)的錯誤。

相關文章