getopt_long()使用方法

本文内容大部分翻译自Linux Man Page
用于学习如何解析命令行参数,其中讲解了getopt、getopt_long、getopt_long_only等函数的用法和区别。

对下文中遇到的词汇做一下约定:
比如在终端输入:find /usr -name “*.txt”
选项:-name
参数:/usr、”*.txt”
选项字符:n
选项元素:-name
argv元素:find、/usr、-name、”*.txt”

概要

#include 

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

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

#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()函数用来解析命令行参数。他的参数argcargv分别是main函数传进来的参数个数和参数列表。如果argv中的元素以’-‘或’–’开头,则该元素是一个选项元素。在这个元素’-‘后面的字符是选项字符。如果getopt()被反复调用,若执行成功,则会返回每个argv 中的选项元素的选项字符

optind变量是个全局变量,表示在argv中将要处理的下个元素的下标。一开始初始化这个值为1。如果需要的话,调用者可以重置它为1,比如在同一个程序中想再重新扫描这个argv,或者处理一个新的参数列表。

如果getopt()发现了另一个选项字符,它会返回这个字符,且更新optind变量和nextchar变量以便于下次调用getopt()函数时可以继续处理下一个选项字符或argv元素

如果没有更多的选项字符,getopt()会返回-1。且optind的值设置为argv中第一个非选项的argv元素

optstring是一个包含了合法选项字符的字符串。如果这个字符后面紧跟一个冒号,则说明这个选项需要一个参数,这个参数可以紧跟在这个选项字符的后面,也可以是下一个argv元素,当optstring为”d:”,且命令行中可以传入”-dabc”,则optarg的值为指向”abc”的指针;如果传入的是”-d abc”,则optarg指向下个argv元素,即”abc”元素。两个冒号意味着可以携带一个可选的参数。如果在这个选项字符后紧接着参数(“-dabc”),则optarg会指向这个参数(“abc”),否则optarg会被设置为0。(使用双冒号后,参数必须紧跟在选项字符后面)

默认情况下,getopt()在扫描argv的内容同时会对它进行重新排序,这样可以使得非选项元素都放在后面。还有其他两种模式,当optstring第一个字符为’+’或环境变量POSIXLY_CORRECT被设置,则getopt()在扫描argv时候一遇到非选项元素时候会停止解析处理(getopt()立即返回-1)。如果optstring第一个字符为’-‘,每个非选项元素会被当做字符值为1(即ASCII码为1)的字符选项的参数,也就是说getopt()返回1。这种模式主要是提供给需要关心选项参数的顺序的调用者。如果指定了”–”选项,会终止getopt()的选项处理(不管何种扫描模式),也就是说一律把”–”后面的argv元素当做参数来处理,即使有元素带’-‘。

getopt()函数遇到一个不认识的选项字符(没有在optstring中出现),它会把错误信息打印在stderr中,并且把字符存在optopt中,然后getopt()会返回’?’。如果你不想打印它打印错误信息,可以设置opterr为0。

getopt()函数遇到一个optstirng中没有的字符,或者检测到某个选项缺少参数,则会返回一个’?’,同时设置optopt的值为这个真实遇到的字符。如果optstring的第一个字符(或者在’+’、’-‘后第一个字符)是’:’,则getopt()在遇到缺少参数的选项时会返回’:’来代替’?’。如果检测到一个错误,且optstring的第一个字符不是一个冒号,且opterr的值为非零,getopt()会打印错误信息。

getopt_long()和getopt_long_only()

getopt_long()getopt()除了支持长选项(以”–”开头)外,其他都一样。(如果程序只接受长选项,optstring应该被指定为空字符串(“”))。长选项可以在保证唯一性的情况下可以简写。一个长选项可以这样携带一个参数:–arg=param或者–arg param

longopts是一个指向struct option数组的第一个元素的指针,struct option(在

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

结构体option各个字段的意思如下:
name
长选项的名字
has_arg
no_argument(或0):选项不携带参数;required_argument(或1):选项需要参数;optional_argument(或2):选项携带可选参数
flag
指定该长选项的返回值。如果flag是NULL,getopt_long会返回val。(比如,调用者可以设置val为短选项字符)否则,getopt_long会返回0,且flag指向的值设置为val的值,前提是该选项成功找到了。
val
当做返回值,或把值加载进flag所指的内存中。

longopts指向的数组的最后一个元素值都设置为0。

如果longindex不是NULL,它指向getopt_long()获得的长选项在longopts的下标。

getopt_long_only()getopt_long()相似,不同的是getopt_long()会把’-‘和”–”都当做一个长选项处理。而getopt_long_only()会把一个以’-‘开头(不是”–”)的选项当做短选项处理。

返回值

如果成功找到了选项,getopt()会返回选项字符。如果所有的命令行都已经解析完了,getopt()会返回-1。如果getopt()遇到一个optstring没有的选项字符,则会返回’?’。如果遇到一个缺少参数的选项字符,返回值就要取决于optstring的第一个字符了:如果是’:’,则返回’:’,否则返回’?’。

环境

POSIXLY_CORRECT
如果该环境变量被设置,选项处理遇到非选项参数会立马停止(即getopt()等方法会立马返回-1)。

注意

一个程序可以解析多个命令行参数数组,或者可以多次解析同一个命令行参数数组,且如果想在多个解析处理之间使用optstring开头的’+’、’-‘,或改变POSIXLY_CORRECT环境变量的值,必须通过设置optind为0来重新初始getopt(),而不是设置为1。

例子

下面的例子使用getopt()来处理两个选项:-n,不携带任何参数;-t val,它携带一个参数


#include 
#include 
#include 

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, "Usage: %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, "Expected argument after options\n");
            exit(EXIT_FAILURE);
    }

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

    /* Other code omitted */

    exit(EXIT_SUCCESS);
}

下面的例子使用了getopt_long()的大多数特性。

#include      /* for printf */
#include     /* for exit */
#include 

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",     required_argument, 0,  0 },
            {"append",  no_argument,       0,  0 },
            {"delete",  required_argument, 0,  0 },
            {"verbose", no_argument,       0,  0 },
            {"create",  required_argument, 0, 'c'},
            {"file",    required_argument, 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("option %s", long_options[option_index].name);
            if (optarg)
                printf(" with arg %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("option %c\n", c);
            break;

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

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

       case 'c':
            printf("option c with value '%s'\n", optarg);
            break;

       case 'd':
            printf("option d with value '%s'\n", optarg);
            break;

       case '?':
            break;

       default:
            printf("?? getopt returned character code 0%o ??\n", c);
        }
    }

   if (optind < argc) {
        printf("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }

   exit(EXIT_SUCCESS);
}

你可能感兴趣的:(Linux)