Getopt可选参数?

16

我有一个程序,你可以输入选项-d,然后无论是否在选项之后提供非必须的参数,都会做一些事情。
这是我的代码:

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

#define OPT_LIST "d::" 

int main (int argc, char *argv[])
{
    int c;
    char string[] = "blah";

    while ((c = getopt (argc, argv, OPT_LIST)) != -1)
    {
        switch (c)
        {
            case 'd':
                    printf("%s\n", optarg);
                    break;

            case '?':
                fprintf(stderr, "invalid option\n");
                exit(EXIT_FAILURE);
        }   
    }
}
如果在选项后输入非可选参数,则会打印该参数。但是如果用户未提供非可选参数,则我希望它能打印出字符“string”(这就是为什么我在OPT_LIST中放置双冒号的原因)。但我不确定如何实现这一点,所以任何帮助都将不胜感激。
当我运行程序时,发生了什么:
user:desktop shaun$ ./arg -d hello
hello
user:desktop shaun$ ./arg -d 
./arg: option requires an argument -- d
invalid option

我正在使用C语言在OS X操作系统下的Mac电脑上运行。


嗯,printf("%s\n", string) - user529758
我希望在运行程序时,它能够打印字符串,例如: ./arg -d - pudumaster
如果将上面的代码行插入到当前 fprintf(stderr, "invalid option\n"); 所在的位置,那么它就会执行相同的操作。 - user529758
我尝试了一下,它打印出了字符串,但同时也打印出了 ./arg: option requires an argument -- d 这个错误信息。你有什么办法可以消除这个错误吗? - pudumaster
1
你无法这样做。需要使用getopt() 来打印诊断信息。 - user529758
4个回答

21
“选项的可选值”特性只是GNU libc的扩展功能,不是POSIX所必需的,在Mac OS X中附带的libc很可能根本未实现此功能。

选项参数是一个字符串,指定此程序有效的选项字符。此字符串中的选项字符后面可以跟着一个冒号(“:”)表示它需要一个必需的参数。如果选项字符后面跟着两个冒号(“::”),则其参数是可选的; 这是GNU的扩展功能。

https://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html

事实上,POSIX.1-2008,第12.2节,“实用程序语法指南”,明确禁止使用此功能:

指南7:选项参数不应为可选。

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02


14
根据 getopt 的文档,如果一个带有参数的选项未获得参数,则它将返回 :。 它还将设置 optopt 为匹配的参数。

因此,请使用:

int main (int argc, char *argv[])
{
    int c;
    while ((c = getopt (argc, argv, ":d:f:")) != -1)
    {
        switch (c)
        {
            case 'd':
            case 'f':
                printf("option -%c with argument '%s'\n", c, optarg);
                break;
            case ':':
                switch (optopt)
                {
                case 'd':
                    printf("option -%c with default argument value\n", optopt);
                    break;
                default:
                    fprintf(stderr, "option -%c is missing a required argument\n", optopt);
                    return EXIT_FAILURE;
                }
                break;
            case '?':
                fprintf(stderr, "invalid option: -%c\n", optopt);
                return EXIT_FAILURE;
        }
    }
    return EXIT_SUCCESS;
}

2
你需要使用 optstring = ":d:f:",并在其前加上一个初始的 :,以允许使用可选参数。非常烦人的是,虽然 foo -dfoo -f arg 可以按预期工作,但是 foo -d -f arg 会误将 -f 当作 -d 的 optarg……有什么巧妙的解决方法吗? - phs
2
@phs,我认为您需要手动检查optarg是否像选项一样(例如,optarg [0] ==' - ' ),如果是,则将optind倒回以读取它(optind-=1;)。如果您想接受负数作为可选参数,则此操作变得更加棘手,这可能是 POSIX 完全禁止负数的原因(指南#7)。参见:https://dev59.com/qXNA5IYBdhLWcg3wNa6T#32575314 - user2975337

4
也许我误解了这个问题。如果用户想要覆盖 getopt 的默认错误处理,那么他们的 OPT_LIST 开头应该有一个 :,是这样吗?我认为上面的代码很好,但是我认为它仍然会打印出错误信息。
./arg: option requires an argument -- d

为了抑制这一点,我们需要在OPT_LIST开头加上一个冒号吗?例如,将此更改为:
while ((c = getopt (argc, argv, "d:f:")) != -1)

转换为:

while ((c = getopt (argc, argv, ":d:f:")) != -1)

如果我错了,请纠正我。


0

尝试这个解决方案。它对我有效。将选项“z”视为带有可选参数的选项。

int c;
opterr = 0; //if (opterr != 0) (which it is by default), getopt() prints its own error messages for invalid options and for missing option arguments.
while ((c = getopt (argc, argv, "x:y:z:")) != -1)
    switch (c)
    {
        case 'x':
        case 'y':
        case 'z':
            printf("OK ... option -%c with argument '%s'\n", c, optarg);
            break;

        case '?':
            if (optopt == 'x' || optopt == 'y')
                fprintf (stderr, "ERR ... Option -%c requires an argument.\n", optopt);
            else if(optopt == 'z' && isprint(optopt))
            {
                printf("OK ... option '-z' without argument \n");
                break;
            }
            else if (isprint (optopt))
                fprintf (stderr, "ERR ... Unknown option `-%c'.\n", optopt);
            else
                fprintf (stderr, "ERR ... Unknown option character `\\x%x'.\n", optopt);
            return -1;
        default: ;
  }

这里有一些例子:
./prog -x
    ERR ... Option -x requires an argument.

./prog -y
    ERR ... Option -x requires an argument.

./prog -z
    OK ... option '-z' without argument

./prog -x aaa
    OK ... option -x with argument 'aaa'

./prog -y bbb -x aaa
    OK ... option -y with argument 'bbb'
    OK ... option -x with argument 'aaa'

./prog -x aaa -y bbb -z
    OK ... option -x with argument 'aaa'
    OK ... option -y with argument 'bbb'
    OK ... option '-z' without argument

./prog -x aaa -y bbb -z ccc
    OK ... option -x with argument 'aaa'
    OK ... option -y with argument 'bbb'
    OK ... option -z with argument 'ccc'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接