Linux中getopt函式、optind等變數使用詳解

men_wen發表於2017-03-13

getopt函式、optind等變數使用詳解

最近在學習《Unix網路程式設計》vol2時,發現書中例子經常使用一個命令列解析getopt函式,因為函式宣告比較特別,根據自己摸索,遂總結出使用方法。

1. getopt函式的宣告

該函式是由Unix標準庫提供的函式,檢視命令man 3 getopt

#include <unistd.h>

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

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

getopt函式的引數:

  • 引數argc和argv:通常是從main的引數直接傳遞而來,argc是引數的數量,argv是一個常量字串陣列的地址。
  • 引數optstring:一個包含正確選項字元的字串,如果一個字元後面有冒號,那麼這個選項在傳遞引數時就需要跟著一個引數。

外部變數:

  • char *optarg:如果有引數,則包含當前選項引數字串
  • int optind:argv的當前索引值。當getopt函式在while迴圈中使用時,剩下的字串為運算元,下標從optind到argc-1。
  • int opterr:這個變數非零時,getopt()函式為“無效選項”和“缺少引數選項,並輸出其錯誤資訊。
  • int optopt:當發現無效選項字元之時,getopt()函式或返回 \’ ? \’ 字元,或返回字元 \’ : \’ ,並且optopt包含了所發現的無效選項字元。

根據下面的程式理解這四個引數

2. getopt函式的使用

man 3 getopt給出了該函式的例子

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

int main(int argc, char *argv[])
{
    int flags = 0, opt;
    int nsecs = 0, tfnd = 0;

    while((opt = getopt(argc, argv, "nt:")) != -1) {
            switch (opt) {
                case 'n':
                    flags = 1;
                    break;
                case 't':
                    nsecs = atoi(optarg);
                    tfnd = 1;
                    break;
                default:
                    printf("optopt = %c\n", (char)optopt);
                    printf("opterr = %d\n", opterr);
                    fprintf(stderr, "usage: %s [-t nsecs] [-n] name\n", argv[0]);
                   exit(EXIT_FAILURE);
            } 
    }
    printf("flags = %d; tfnd = %d; nsecs = %d; optind = %d\n", flags, tfnd, nsecs, optind);

    printf("optind = %d\n", optind);
    printf("argc = %d\n", argc);
#if 1 
    if(optind >= argc) {
        fprintf(stderr, "Expected argument after options\n"); 
        exit(1);
    }
#endif
    printf("name argument = %s\n", argv[optind]);
    /* Other code omitted */
    return 0;
}
  • getopt函式的第三個字串引數 “nt:”:在man page中這樣解釋:-n, with no associated value; and -t val, which expects an associated value。中文意思為:-n 不用一個關聯值;-t 需要有一個關聯的value引數

執行結果:

➜  test ./a.out -a  name    //首先 -a 是一個非法的選項
./a.out: invalid option -- 'a'  //輸出錯誤資訊,因為非法選項
optind = 2  //此時argv[optind]是我們的運算元,也就是我們傳遞給主函式的引數
optopt = a  //當發現無效項字元時,optopt會包含該字元,正如我們傳遞的‘a’這個無效項。
opterr = 1  //opterr變數非零,getopt()函式為“無效選項”和“缺少引數選項,並輸出其錯誤資訊。
usage: ./a.out [-t nsecs] [-n] name

再次執行:

➜  test ./a.out -t        //根據getopt函式的第三個引數,因為‘t’字元後有‘:’冒號,因此在‘-t’選項後需要跟隨一個引數。因此此次執行的錯誤為“缺少引數”,如下提示:
./a.out: option requires an argument -- 't' //輸出了錯誤資訊,因為“缺少引數”
optind = 2  //argv[optind]為空,因為此次執行沒有傳遞引數
optopt = t  //當發現無效項字元時,optopt會包含該字元,正如我們傳遞的‘t’缺少引數的選項。
opterr = 1  //opterr變數非零,getopt()函式為“無效選項”和“缺少引數“選項,並輸出其錯誤資訊。
usage: ./a.out [-t nsecs] [-n] name

再次執行:

➜  test ./a.out -t 123 -n     //此時,根據字串”-nt:“應該得知,-t 後應加引數,-n不用加
flags = 1; tfnd = 1; nsecs = 123; optind = 4    //在switch語句中將flags=1,tfnd=1,因為optarg變數儲存這當前選項引數的字串,因此此時optarg儲存的是‘-t’引數的引數並用atoi函式轉稱整數,因此nsecs=123。
optind = 4  //argv[optind]為空,因為沒有向主函式傳遞引數
argc = 4    //一共四個字串
Expected argument after options //該程式希望我們至少傳遞一個引數,因此在if語句中退出。

再次執行:

➜  test ./a.out -t 123 -n hello //‘-t’後加引數,‘-n’不用加,向main函式傳遞引數叫hello
flags = 1; tfnd = 1; nsecs = 123; optind = 4
optind = 4  //argv[optind] = ”hello“
argc = 5    //五個字串
name argument = hello   //列印引數name argument= hello

其實可以傳遞多個引數(如果需要,因為此函式只列印第一個引數),例如:

➜  test ./a.out -t 123 -n hello world hello C
optind = 3
optind = 4
flags = 1; tfnd = 1; nsecs = 123; optind = 4
optind = 4
argc = 8
name argument = hello   

相關文章