【轉】getopt分析命令列參數

來源:互聯網
上載者:User

標籤:

(一)

在Linux中,用命令列執行可執行檔時可能會涉及到給其加入不同的參數的問題,例如:

./a.out -a1234 -b432 -c -d


程式會根據讀取的參數執行相應的操作,在C語言中,這個功能一般是靠getopt()這個函數,結合switch語句來完成的,首先來看下面的代碼:

#include <stdio.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
  int ch;
  opterr=0;
  
  while((ch=getopt(argc,argv,"a:b::cde"))!=-1)
  {
    printf("optind:%d\n",optind);
    printf("optarg:%s\n",optarg);
    printf("ch:%c\n",ch);
    switch(ch)
    {
      case ‘a‘:
        printf("option a:‘%s‘\n",optarg);
        break;
      case ‘b‘:
        printf("option b:‘%s‘\n",optarg);
        break;
      case ‘c‘:
        printf("option c\n");
        break;
      case ‘d‘:
        printf("option d\n");
        break;
      case ‘e‘:
        printf("option e\n");
        break;
      default:
        printf("other option:%c\n",ch);
    }
    printf("optopt+%c\n",optopt);
  }

}    


用gcc編譯後,在終端行執行以上的命令:

./a.out -a1234 -b432 -c -d


則會有如下的輸出:

optind:2
optarg:1234
ch:a
option a:‘1234‘
optopt+
optind:3
optarg:432
ch:b
option b:‘432‘
optopt+
optind:4
optarg:(null)
ch:c
option c
optopt+
optind:5
optarg:(null)
ch:d
option d
optopt+

要理解getopt()函數的作用,首先要清楚帶參數的main()函數的使用:
main(int argc,char *argv[])中的argc是一個整型,argv是一個指標數組,argc記錄argv的大小。上面的例子中。
argc=5;
argv[0]=./a.out
argv[1]=-a1234
argv[2]=-b432
argv[3]=-c
argv[4]=-d
getopt()函數的原型為getopt(int argc,char *const argv[],const char *optstring)。
其中argc和argv一般就將main函數的那兩個參數原樣傳入。
optstring是一段自己規定的選項串,例如本例中的"a:b::cde",表示可以有,-a,-b,-c,-d,-e這幾個參數。
“:”表示必須該選項帶有額外的參數,全域變數optarg會指向此額外參數,“::”標識該額外的參數可選(有些Uinx可能不支援“::”)。
全域變數optind指示下一個要讀取的參數在argv中的位置。
如果getopt()找不到符合的參數則會印出錯資訊,並將全域變數optopt設為“?”字元。
如果不希望getopt()印出錯資訊,則只要將全域變數opterr設為0即可。

 

 

 

(二)

#include <unistd.h>
       extern char *optarg;  //選項的參數指標
       extern int optind,   //下一次調用getopt的時,從optind儲存的位置處重新開始檢查選項。 
       extern int opterr,  //當opterr=0時,getopt不向stderr輸出錯誤資訊。
       extern int optopt;  //當命令列選項字元不包括在optstring中或者選項缺少必要的參數時,該選項儲存在optopt中,getopt返回‘?’、
       int getopt(int argc, char * const argv[], const char *optstring);
 調用一次,返回一個選項。 在命令列選項參數再也檢查不到optstring中包含的選項時,返回-1,同時optind儲存第一個不包含選項的命令列參數。

首先說一下什麼是選項,什麼是參數。

字串optstring可以下列元素,
1.單個字元,表示選項,
2.單個字元後接一個冒號:表示該選項後必須跟一個參數。參數緊跟在選項後或者以空格隔開。該參數的指標賦給optarg。
3 單個字元後跟兩個冒號,表示該選項後必須跟一個參數。參數必須緊跟在選項後不能以空格隔開。該參數的指標賦給optarg。(這個特性是GNU的擴張)。

getopt處理以‘-’開頭的命令列參數,如optstring="ab:c::d::",命令列為getopt.exe -a -b host -ckeke -d haha 
在這個命令列參數中,-a和-h就是選項元素,去掉‘-‘,a,b,c就是選項。host是b的參數,keke是c的參數。但haha並不是d的參數,因為它們中間有空格隔開。

還要注意的是預設情況下getopt會重新排列命令列參數的順序,所以到最後所有不包含選項的命令列參數都排到最後。
如getopt.exe -a ima -b host -ckeke -d haha, 都最後命令列參數的順序是: -a -b host -ckeke -d ima haha
如果optstring中的字串以‘+‘加號開頭或者環境變數POSIXLY_CORRE被設定。那麼一遇到不包含選項的命令列參數,getopt就會停止,返回-1。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int result;

    opterr = 0;  //使getopt不行stderr輸出錯誤資訊

    while( (result = getopt(argc, argv, "ab:c::")) != -1 )
    {
           switch(result)
          {
               case ‘a‘:
                   printf("option=a, optopt=%c, optarg=%s\n", optopt, optarg);
                   break;
              case ‘b‘:
                   printf("option=b, optopt=%c, optarg=%s\n", optopt, optarg);
                   break;
              case ‘c‘:
                   printf("option=c, optopt=%c, optarg=%s\n", optopt, optarg);
                   break;
              case ‘?‘:
                    printf("result=?, optopt=%c, optarg=%s\n", optopt, optarg);
                    break;
              default:
                   printf("default, result=%c\n",result);
                   break;
           }
        printf("argv[%d]=%s\n", optind, argv[optind]);
    }
    printf("result=-1, optind=%d\n", optind);   //看看最後optind的位置

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

 //看看最後的命令列參數,看順序是否改變了哈。
    for(result = 1; result < argc; result++)
          printf("\nat the end-----argv[%d]=%s\n", result, argv[result]);
    return 0;
}

unistd裡有個 optind 變數,每次getopt後,這個索引指向argv裡當前分析的字串的下一個索引,因此
argv[optind]就能得到下個字串,通過判斷是否以 ‘-‘開頭就可。下面是個測試程式
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
    int tmp = 4;
    
    while( (tmp = getopt(argc, argv, "abck")) != -1  )
    {
           
           printf("-%c\t", tmp);
           int opt = optind ;
           while( opt < argc )
           {
                  if ( argv[opt][0] != ‘-‘ )
                  {
                       printf("%s\t", argv[opt]);
                       opt ++;
                  }
                  else
                      break;
           }
           printf("\n");
    }
    getchar();
}
函數說明  getopt()用來分析命令列參數。參數argc和argv是由main()傳遞的參數個數和內容。參數optstring 則代表欲處理的選項字串。此函數會返回在argv 中下一個的選項字母,此字母會對應參數optstring 中的字母。如果選項字串裡的字母后接著冒號“:”,則表示還有相關的參數,全域變數optarg 即會指向此額外參數。如果getopt()找不到符合的參數則會印出錯資訊,並將全域變數optopt設為“?”字元,如果不希望getopt()印出錯資訊,則只要將全域變數opterr設為0即可。

傳回值  如果找到符合的參數則返回此參數字母,如果參數不包含在參數optstring 的選項字母則返回“?”字元,分析結束則返回-1。

範例  #include<stdio.h>
#include<unistd.h>
int main(int argc,char **argv)
{
int ch;
opterr = 0;
while((ch = getopt(argc,argv,”a:bcde”))!= -1)
switch(ch)
{
case ‘a’:
printf(“option a:’%s’\n”,optarg);
break;
case ‘b’:
printf(“option b :b\n”);
break;
default:
printf(“other option :%c\n”,ch);
}
printf(“optopt +%c\n”,optopt);
}

執行  $./getopt –b
option b:b
$./getopt –c
other option:c
$./getopt –a
other option :?
$./getopt –a12345
option a:’12345’


getopt 函數
函數定義:
#include 
int getopt(int argc, char * const argv[], 
        const char *optstring);

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


#define _GNU_SOURCE
#include

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);


getopt()函數是用來解析命令列參數的。這裡,主要解釋getopt_long()。

    getopt_long()的頭兩參數,argc和argv分別是傳遞給main()的參數的個數和參數數組(和main()的argc和argv是一個概念)。

    getopt_long()中,optstring是一個字串,表示可以接受的參數。例如,"a:b:cd",表示可以接受的參數是a,b,c,d,其中,a和b參數後面

跟有更多的參數值。(例如:-a host --b name)

    getopt_long()中,參數longopts,其實是一個結構的執行個體:
struct option {
  const char *name;
    //name表示的是長參數名
  int has_arg;
    //has_arg有3個值,no_argument(或者是0),表示該參數後面不跟參數值
    //   required_argument(或者是1),表示該參數後面一定要跟個參數值
    //   optional_argument(或者是2),表示該參數後面可以跟,也可以不跟參數值
  int *flag;
    //用來決定,getopt_long()的傳回值到底是什麼。如果flag是null,則函數會返回與該項option匹配的val值
  int val;
    //和flag聯合決定傳回值
}

給個例子:

struct option long_options[] = {
  {"a123",       required_argument,      0, ‘a‘},
  {"c123",       no_argument,            0, ‘c‘},
}

現在,如果命令列的參數是-a 123,那麼調用getopt_long()將返回字元‘a‘,並且將字串123由optarg返回(注意注意!字串123由optarg帶

回!optarg不需要定義,在getopt.h中已經有定義)
那麼,如果命令列參數是-c,那麼調用getopt_long()將返回字元‘c‘,而此時,optarg是null。

最後,當getopt_long()將命令列所有參數全部解析完成後,返回-1。

看來,我說的有點混亂,那麼,看個例子,我相信,代碼最能說明問題:

#include 
#include 
#include 
#include

int main( int argc, char **argv )
{

 struct option long_options[] = {
   {"a123",       required_argument,      0, ‘a‘},
   {"c123",       no_argument,            0, ‘c‘},
 }
 int opt;
 
 printf("starting... ");
 
 while((opt = getopt_long(argc, argv, "a:c", long_options, NULL)) != -1)
 {
  switch (opt)
  {
  case ‘a‘:
    printf("It‘s a! ");
    printf("string of a:%s ",optarg);
  break;
    
  case ‘c‘:
    printf("It‘s c! ");
  break;
    
  default:
    printf("You should look for help! ");
    exit(1);
  break;            
  }
 }
 printf("end... ");
 return 0;
}

編譯後,假設產生a.out,可以實驗一下。
./a.out -a hello -c
輸出:
starting...
It‘s a!
string of a:hello
It‘s c!
end...

【轉】getopt分析命令列參數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.