上一頁 | 首頁

getopt

章節:Linux 程序員手冊 (3)
更新:2008-08-29
索引  

名稱

getopt、getopt_long、getopt_long_only、optarg、optind、opterr、optopt - 分析命令行選項  

摘要

#include <unistd.h>

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

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

#include <getopt.h>

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

glibc的特征測試宏要求(Feature Test Macro Requirements)(參見 feature_test_macros(7)):

getopt(): _POSIX_C_SOURCE >= 2 || _XOPEN_SOURCE || _POSIX_SOURCE
getopt_long()、 getopt_long_only(): _GNU_SOURCE  

描述

getopt() 函數用于分析命令行參數。它的參數 argcargv 跟程序調用時傳遞給 main() 函數的類似,是參數數量及參數數組。 以'-'開頭(嚴格地說,是"-"或"--")的argv元素是選項元素。用以表示該元素的字符串(包含開頭的'-')是選項字符串。若反復調用 getopt() ,則它會一個接一個地返回相應于各個選項元素的各個選項字符。

變量 optindargv 中下一個要處理的元素的下標。系統將其初始化為1。調用者可以將其重置為1(譯注:此處當為筆誤,下文"備注"一節說是"將其重置為0",而且實際上,將其重置為0才能達到重新初始化getopt()的目的),以重新掃描同一個 argv 或重新掃描新的參數數組。

getopt() 找到另一個選項字符,則它返回那個字符,並更新外部變量optind、靜態變量nextchar,以期下次調用 getopt() 時,可以繼續掃描後續選項字符、argv元素。

若不再有選項字符串,則 getopt() 返回-1。此時,optind是第一個非選項argv元素的下標。

optstring 是包含有效選項的字符串。若這樣的字符後接一個冒號,則選項要求一個參數。因此, getopt() 設置一個指向同一個argv元素的後續文本的指針,或指向 下一个argv元素的指針,而 optarg 存儲了該元素(譯注:若選項與選項參數間有空白符時,則發生第一種情況;否則,發生第二種情況)。兩個冒號表示選項需要一個可選參數;若當前argv元素尚有文本(譯注:指當前argv元素在選項字符之後尚有字符)(譬如:其與選項名稱同名,如"-oarg"),則它由optarg返回,否則將optarg設置為0。這是一個GNU擴展。若 optstring 包含後接分號的 W ,則 -W foo 等價于長選項 --foo。 (POSIX.2為實現的擴展保留 -W 選項。)這種行為屬于GNU擴展,在glibc 2之前的庫中不可用。

getopt() 默認會改變其所掃描到的argv元素的次序,以期最終所有非選項元素都放置于最後。另外實現了兩種模式:若optstring的第一個字符為'+',或者設置了環境變量 POSIXLY_CORRECT ,則在處理選項時,一遇到非選項參數(譯注:這裡所說的"參數"是指命令行參數,也就是argv元素。下文為方便起見,當"參數"是指命令行參數時,將其譯為"argv元素"、"元素"或"選項")就停止;若optstring的第一個字符為'-',則將每個非選項argv元素當作字符編碼為1的選項元素來處理。(這用于編寫期望選項與其他argv元素以任意次序排列而又關注兩者的次序的程序。)"--"這個特殊參數強制忽略掃描模式並終止掃描選項。

getopt() 認不出某個選項字符,則它向stderr打印一條出錯信息,並在將該字符保存到optopt之後返回'?'。調用程序可通過將opterr設置為0來防止打印出錯信息。

getopt() 發現一個不包含于optstring之中的選項字符,或者發現一個遺漏了參數的選項,則它返回'?',並將外部變量optopt設置為實際的選項字符。若optstring的第一個字符(若存在上述任一可選的'+'或'-',則從其後計起)是冒號(':'),則 getopt() 返回':',而非'?',以指示遺漏了選項參數。若發現了錯誤,而optstring的第一個參數(譯注:計數方式同上)不是冒號,且外部變量opterr不為0(這是默認值),則 getopt() 打印一條出錯信息。

getopt_long()和getopt_long_only()

除了同時接受以兩個破折號(譯注:此處指西文破折號。在鍵盤上,它跟負號、減號、連字符指的是同一個鍵)開頭的長選項之外, getopt_long() 函數的操作跟 getopt() 類似。(若程序僅僅接受長選項,則應當將 optstring 設置為空字符串(""),而非NULL。)長選項可以使用縮寫,但要求該縮寫是唯一的,或與某個已定義的選項一模一樣。長選項可以使用 --arg=param--arg param 參數格式。

longopts 是一個指向 struct option 數組的第一個元素的指針。該結構體像如下所示那樣聲明于 <getopt.h>


struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};

各個成員的含義如下:

name
長選項名。
has_arg
若選項沒有參數,則為no_argument (或0);若選項需要一個參數,則為required_argument(或1);若選項有一個可選參數,則為optional_argument(或2)。
flag
指定為長選項返回結果的方式。若flag為NULL,則 getopt_long() 返回val(譬如:調用程序會將val設置為等價的短選項字符)。否則, getopt_long() 返回0;並且,若找到選項,則將val的值賦給flag所指向的變量;若找不到,則flag所指向的變量保持不變。
val
所要返回的值,或者是所要賦給由flag所指向的變量的值。

必須要以0來填充數組的最後一個元素。

longindex不為NULL,則它指向一個值為與 longopts 相應的長選項的下標值的變量。

getopt_long_only() 跟 getopt_long() 類似,但'-'和"--"都可以作為長選項標識。若以'-'(而非"--")開頭的選項沒有與之相匹配的長選項,但有與之相匹配的短選項,則將其看作短選項。  

返回值

若成功查找到選項,則 getopt() 返回選項字符。若分析完所有命令行選項,則 getopt() 返回-1。若 getopt() 遇到不包含于 optstring 之中的選項字符,則返回'?'。若 getopt() 遇到遺漏參數的選項,則返回值取決于以下包含于 optstring 之中的第一個字符:若其為':',則返回':';否則,返回'?'。

getopt_long() 和 getopt_long_only() 識別出短選項時,也會返回選項字符。對于長選項,若flag為NULL,則它們返回val;否則,返回0。對于 getopt() 而言,出錯跟返回-1是一樣的(譯注:言下之意,即是不會出錯,返回-1僅僅表示分析完所有命令行選項)。另外,若選項無效或選項缺失參數,則返回'?'。  

環境

POSIXLY_CORRECT
若設置它,則一遇到非選項元素就就停止分析選項。
_<PID>_GNU_nonoption_argv_flags_
bash(1) 2.0版用此變量通知glibc展開通配符之後會得到哪些參數,從而不應將其視為選項。 bash(1) 2.01版已經取消了這種行為,但glibc仍然支持它。
 

遵從

getopt():
POSIX.2和POSIX.1-2001,假定設置環境變量 POSIXLY_CORRECT 。另外,argv元素不是一個真正的常量。這是由于我們會改變其次序。我們在原型裡將其標識為常量以兼容其他系統。

optstring 中使用'+'和'-'是一種GNU擴展。

對于一些較舊的實現, getopt() 被聲明于 <stdio.h>。 SUSv1(譯注:Single UNIX Specification version 1,單一UNIX規範第1版)允許將其聲明于 <unistd.h><stdio.h>。 POSIX.1-2001指出為此而使用 <stdio.h> 是一種過時的做法。POSIX.1-2001不允許將其聲明于 <stdio.h>

getopt_long()和getopt_long_only():
這些函數是一種GNU擴展。
 

備注

對于掃描多個參數數組或多次重新掃描同一個數組並希望利用諸如 optstring 開頭的 '+'和'-'或掃描期間改變 POSIXLY_CORRECT 的值的程序,必須通過將缺省值為1的 optind 設置為0來重新初始化 getopt()。 (重置為0以強制調用用于重新檢測 POSIXLY_CORRECT 及檢測 optstring 中的GNU擴展的內部初始化例程。)  

漏洞

在POSIX.2中, getopt() 規範有一個描述于POSIX.2第150號解釋的技術錯誤。對此,GNU的實現(也許是所有其他的實現)實現了正確的行為。  

實例

以下這個小小的實例程序用 getopt() 來處理兩個程序選項: -n, 沒有相關值; -t val, 期望一個相關值。

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

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

    nsecs = 0;
    tfnd = 0;
    flags = 0;
    while ((opt = getopt(argc, argv, "nt:")) != -1) {
        switch (opt) {
        case 'n':
            flags = 1;
            break;
        case 't':
            nsecs = atoi(optarg);
            tfnd = 1;
            break;
        default: /* '?' */
            fprintf(stderr, "用法:%s [-t nsecs] [-n] name\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    printf("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);

    if (optind >= argc) {
        fprintf(stderr, "選項之後應當有參數\n");
        exit(EXIT_FAILURE);
    }

    printf("name參數 = %s\n", argv[optind]);

    /* 省略其他代碼 */

    exit(EXIT_SUCCESS);
}

以下實例程序通過 getopt_long() 的大量特性來闡明其用法。


#include <stdio.h>     /* 為了支持printf */
#include <stdlib.h>    /* 為了支持exit */
#include <getopt.h>

int
main(int argc, char **argv)
{
    int c;
    int digit_optind = 0;

    while (1) {
        int this_option_optind = optind ? optind : 1;
        int option_index = 0;
        static struct option long_options[] = {
            {"add", 1, 0, 0},
            {"append", 0, 0, 0},
            {"delete", 1, 0, 0},
            {"verbose", 0, 0, 0},
            {"create", 1, 0, 'c'},
            {"file", 1, 0, 0},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "abc:d:012",
                 long_options, &option_index);
        if (c == -1)
            break;

        switch (c) {
        case 0:
            printf("選項%s", long_options[option_index].name);
            if (optarg)
                printf("帶有參數%s", optarg);
            printf("\n");
            break;

        case '0':
        case '1':
        case '2':
            if (digit_optind != 0 && digit_optind != this_option_optind)
              printf("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf("選項%c\n", c);
            break;

        case 'a':
            printf("選項a\n");
            break;

        case 'b':
            printf("選項b\n");
            break;

        case 'c':
            printf("選項c,其參數為'%s'\n", optarg);
            break;

        case 'd':
            printf("選項d,其參數為'%s'\n", optarg);
            break;

        case '?':
            break;

        default:
            printf("?? getopt所返回的字符編碼為0%o ??\n", c);
        }
    }

    if (optind < argc) {
        printf("非選項argv元素:");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }

    exit(EXIT_SUCCESS);
}

 

參見

getsubopt(3)、 feature_test_macros(7)

 

尾署

此頁為第3.22版Linux手冊頁(man-pages)項目的一部份。可以從http://www.kernel.org/doc/man-pages/找到此項目的說明以及關于報告漏洞的信息。


 

譯者補充

 

术语解析

由于英文手册有时将argument解释为命令行参数,有时解析为选项的参数,相当混乱。在這裡,有必要集中澄清一下一些概念:
命令行選項
顧名思義,就是命令的選項,也就是getopt()argv參數的各個元素。以'-'或"--"開頭,並且在optstring或longopts有相應的定義的選項是有效選項;否則,是無效選項。
命令行參數
與命令行選項同義。
選項元素
與命令行選項同義。
選項
與命令行選項同義。
argv元素
與命令行選項同義。
選項字符串
與命令行選項同義。
選項字符
以'-'開頭並且其後只有一個字符的argv元素叫短選項,其中,'-'之後的字符叫選項字符。如果optstring也含有該字符,則該選項字符是有效的;否則,是無效選項字符。
選項參數
顧名思義,是選項的參數,也就是argv中排在有效選項元素之後的元素。

 

漏洞

短選項與其可選參數間不能有空白符,否則參數解析錯誤;長選項與其可選項間只能以'='連接,否則解析錯誤。

 

實例

1. getopt()


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

void get_opt(int argc, char *const *argv, const char *optstring);

int main(int argc, char **argv)
{
    int i;
    const char optstring[2][8]=
    {
        /* 一遇到非選項參數就停止,並返回'?' */
        "+ab:c::",
        /* 將每個非選項argv元素當作字符編碼為1的選項來處理,並返回':' */
        "-:ab:c::",
    };

    for(i=0; i<2; i++)
    {
        printf("--------- %c模式 ---------\n", optstring[i][0]);
        optind=0;   /* 重新初始化getopt() */
        get_opt(argc, argv, optstring[i]);
    }
    exit(EXIT_SUCCESS);
}

void get_opt(int argc, char * const *argv, const char *optstring)
{
    int c;
    while (1)
    {
        optopt=-1;
        c=getopt(argc, argv, optstring);
        if (c == -1)
            break;

        switch (c)
        {
            case 'a':
                printf("選項a\n");
                break;
            case 'b':
                printf("選項b,其參數為\"%s\"\n", optarg);
                break;
            case 'c':
                printf("選項c,", optarg);
                if(optarg != NULL)
                    printf("其參數為\"%s\"\n", optarg);
                else
                    printf("没有參數\n");
                break;
            case '?':
            case ':':
                if(strchr(optstring, optopt) == NULL)
                    printf("無效選項字符:%c\n", optopt);
                else
                    printf("遺漏了參數的選項字符:%c\n", optopt);
                break;
            case 1:
                printf("非選項元素%s\n", optarg);
        }
    }
    if(optind < argc)
    {
        int i=1;
        printf("非選項元素:");
        while(optind < argc)
            printf("\n%d. %s", i++, argv[optind++]);
        printf("\n");
    }
}

2. getopt_long


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

void get_opt(int argc, char *const *argv, const char *optstring,
             const struct option *longopts, int *longindex);

int main(int argc, char **argv)
{
    int i, longindex;
    int x=1;
    const char optstring[2][9]=
    {
        "aW;b:c::",
        "",
    };
    struct option longopts[]=
    {
        {"again",      no_argument,       NULL,     'a'},
        {"agn",        no_argument,       NULL,     'a'},
        {"block-size", required_argument, NULL,     'b'},
        {"counts",     optional_argument, &x,       'c'},
        {NULL,         0,                 NULL,      0 },
    };
    for(i=0; i<2; i++)
    {
        optind=0;
        printf("----------------------------------------------\n");
        get_opt(argc, argv, optstring[i], longopts, &longindex);
    }
    exit(EXIT_SUCCESS);
}

void get_opt(int argc, char * const *argv, const char *optstring,
             const struct option *longopts, int *longindex)
{
    int c;
    while (1)
    {
        c=getopt_long(argc, argv, optstring, longopts, longindex);
        if (c == -1)
            break;
        switch (c)
        {
            case 'a':
                printf("選項a\n");
                break;
            case 'b':
                printf("選項b,其參數為\"%s\"\n", optarg);
                break;
            case 'c':
                printf("選項c,", optarg);
                if(optarg != NULL)
                    printf("其參數為\"%s\"\n", optarg);
                else
                    printf("没有參數\n");
                break;
            case 0:
                printf("flag=%d, val=%d, &flag=%p, &val=%p\n",
                        *(longopts[*longindex].flag),
                        (longopts+*longindex)->val,
                        longopts[*longindex].flag,
                        &(longopts+*longindex)->val);
            case '?':
                /* 若選項無效或選項缺失參數,则会返回'?'。查找
                   出现此情况的确切原因的代码比较长,这里省略,由
                   optget*()自身去报告。*/
                break;
            case 'W':
                /* 当optstring含有后接分号的'W'时,getopt*()会将"-W"
                   后的选项当作长选项,但它不能检测出该长选项是否有效。
                   如果你 * 想检测的话,唯有自己动手了。这里省略。 */
                break;
        }
    }

    if(optind < argc)
    {
        int i=1;
        printf("非選項元素:");
        while(optind < argc)
            printf("\n%d. %s", i++, argv[optind++]);
        printf("\n");
    }
}

3. getopt_long_only()


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

void get_opt(int argc, char *const *argv, const char *optstring,
             const struct option *longopts, int *longindex);

int main(int argc, char **argv)
{
    int i, longindex;
    const char optstring[2][9]=
    {
        "ab:c::",
        "",
    };
    struct option longopts[]=
    {
        {"again",      no_argument,       NULL,     'a'},
        {"block-size", required_argument, NULL,     'b'},
        {"counts",     required_argument, NULL,     'c'},
        {"abc",        no_argument,       NULL,     'd'},
        {NULL,         0,                 NULL,      0 },
    };
    for(i=0; i<2; i++)
    {
        optind=0;
        printf("----------------------------------------------\n");
        get_opt(argc, argv, optstring[i], longopts, &longindex);
    }
    exit(EXIT_SUCCESS);
}

void get_opt(int argc, char * const *argv, const char *optstring,
             const struct option *longopts, int *longindex)
{
    int c;
    while (1)
    {
        c=getopt_long_only(argc, argv, optstring, longopts, longindex);
        if (c == -1)
            break;
        switch (c)
        {
            case 'a':
                printf("選項a\n");
                break;
            case 'b':
                printf("選項b,其參數為\"%s\"\n", optarg);
                break;
            case 'c':
                printf("選項c,", optarg);
                if(optarg != NULL)
                    printf("其參數為\"%s\"\n", optarg);
                else
                    printf("没有參數\n");
                break;
            case 'd':
                printf("選項d,其參數為\"%s\"\n", optarg);
                break;
            case '?':
                opterr=0;   /* 防止getopt()报告错误 */
                printf("選項無效或選項缺失參數\n");
                break;
        }
    }

    if(optind < argc)
    {
        int i=1;
        printf("非選項元素:");
        while(optind < argc)
            printf("\n%d. %s", i++, argv[optind++]);
        printf("\n");
    }
}

 

譯者

石仔<guoshimin57@gmail.com>  

中文版主頁

http://guoshimin.users.sf.net  

中文版最後更新時間

2010年3月7日


 

索引

名稱
摘要
描述
返回值
環境
遵從
備注
漏洞
實例
參見
尾署

譯者補充

术语解析
漏洞
實例

譯者
中文版主頁
中文版最後更新時間


版權 © 2024 石仔