首页 > 解决方案 > getopt() 解析模式不起作用

问题描述

根据手册页, getopt() 具有三种不同的解析模式

默认情况下,getopt() 会在扫描时置换 argv 的内容,以便最终所有非选项都位于末尾。还实现了另外两种模式。如果 optstring 的第一个字符是 '+' 或设置了环境变量 POSIXLY_CORRECT,则一旦遇到非选项参数,选项处理就会停止。如果 optstring 的第一个字符是 '-',则每个非选项 argv- 元素都被处理为就好像它是具有字符代码 1 的选项的参数一样。(这被编写为期望选项和其他 argv 元素的程序使用以任何顺序,并且关心两者的顺序。)特殊参数“--”强制结束选项扫描,而不管扫描模式如何。

在我的 Centos 7 上,似乎 '+'/'-' 符号无法切换解析模式,它们都给出相同的结果,这是我的测试代码:

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

void parse(int argc, char * const argv[], const char *optstr)
{
    printf("opterr: %d optstr: %s optargs: ", opterr, optstr);
    for (int i = 0; i < argc; ++i) {
        printf("%s ", argv[i]);
    }
    printf("\n");

    int opt = -1;
    optind = 1;
    while ((opt = getopt(argc, argv, optstr)) != -1) {
        printf("optind: %d optopt: %d "
               "optarg: %s opt: %c\n",
               optind, optopt, optarg, (char)opt);
    }

    printf("unparsed: ");
    for (int i = optind; i < argc; ++i) {
        printf("%s ", argv[i]);
    }
    printf("\n");
}

void nonoption()
{
    const char *optstr = "ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

void posix_nonoption()
{
    const char *optstr = "+ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

void nonoption1()
{
    const char *optstr = "-ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

int main(int argc, char *argv[])
{
    nonoption();
    posix_nonoption();
    nonoption1();
    return 0;
}

这是输出:

opterr: 1 optstr: ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world
opterr: 1 optstr: +ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world
opterr: 1 optstr: -ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world

标签: clinuxunixglibc

解决方案


如果你看一下getopt 手册,你会发现这一段:

扫描多个参数向量,或多次重新扫描同一个向量,并希望在 optstring 的开头使用 GNU 扩展,例如 '+' 和 '-',或在扫描之间更改 POSIXLY_CORRECT 的值的程序,必须通过将 optind 重置为 0 而不是传统值 1 来重新初始化 getopt()。(重置为 0 会强制调用内部初始化例程,该例程重新检查 POSIXLY_CORRECT 并检查 optstring 中的 GNU 扩展。)

您必须设置optind0in function parse,然后它将起作用。


推荐阅读