关于getopt:将long选项作为short选项的参数时-getopt_long

when long option is given as argument to short option - getopt_long

我正在学习如何使用getopt_long函数接受命令行参数,我设置了2个长选项'filename'(必需的arg)和'clear'(没有arg)以及2个简短的args'a'(带有arg)和'b'(没有 arg)当我执行时:

1
$ ./a.out -a --filename=test.txt

而不显示'a'没有arg,而是显示'a'的optarg为:
--filename = text.txt并跳过文件名长选项
有什么解决办法吗?

我的代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <getopt.h>

using namespace std;



int main(int argc, char* argv[]){

    static struct option long_options[] = {
        {"filename",1,0,0},
        {"clear",0,0,0},
        {NULL,0,0,0}
    };

    int op,option_index = 0;
    string filename;
    while((op = getopt_long(argc,argv,"a:b",long_options,&option_index))!=-1){
        switch (op){
            case 0:
                switch(option_index){
                    case 0:
                        filename = optarg;
                        cout<<filename<<endl;
                        break;
                    case 1:
                        cout<<"clear is yes
";
                        break;
                    default:
                        cout<<"Please enter valid long option
";
                        break;
                }break;
            case 'a':
                cout<<"a is set as"<<optarg<<endl;
                //cout<<optarg<<endl;
                break;
            case 'b':
                cout<<"b is set"<<endl;
                    break;
            default:
                cout<<"Please enter valid Arguments"<<endl;
                break;
        }
    }
    cout<<"

";

    return 0;
}


我找到了一个更好的答案,我的朋友告诉我。

我可以直接使用::代替:这意味着'a'需要一个可选参数,因此getopt_long将检查arg是否为选项,如果没有arg或arg为选项,则返回0,我可以单独处理,如果'a'具有非选项arg,那里的情况可以正常处理。

最终代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <getopt.h>

using namespace std;



int main(int argc, char* argv[]){

    static struct option long_options[] = {
        {"filename",1,0,0},
        {"clear",0,0,0},
        {NULL,0,0,0}
    };

    int op,option_index = 0;
    string filename;
    while((op = getopt_long(argc,argv,"a::b",long_options,&option_index))!=-1){
        switch (op){
            case 0:
                switch(option_index){
                    case 0:
                        filename = optarg;
                        cout<<filename<<endl;
                        break;
                    case 1:
                        cout<<"clear is yes
";
                        break;
                    default:
                        cout<<"Please enter valid long option
";
                        break;
                }break;
            case 'a':
                if(optarg)
                    cout<<"a is set as"<<optarg<<endl;
                else
                    cout<<"a needs an argument"<<endl;
                //cout<<optarg<<endl;
                break;
            case 'b':
                cout<<"b is set"<<endl;
                    break;
            default:
                cout<<"Please enter valid Arguments"<<endl;
                break;
        }
    }
    cout<<"

";

    return 0;
}

无需对此进行任何硬编码。


一种方法是查看-a的参数,看看它是否真的是一个选项。如果是这样,请处理错误并设置optind -= 1,以便getopt_long()进行的进一步处理将错误地跟随-a的选项视为选项。虽然不是特别优雅,但确实可行。

这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <getopt.h>

#include <string.h>

using namespace std;


int str_startswith( char const* s, char const* prefix)
{
    return strncmp(prefix, s, strlen(prefix)) == 0;
}


bool is_option(char const* arg)
{
    int result = 0;

    result = result || str_startswith( arg,"--filename=");
    result = result || (strcmp( arg,"--clear") == 0);
    result = result || (strcmp( arg,"-b") == 0);

    return result;
}



int main(int argc, char* argv[]){

    static struct option long_options[] = {
        {"filename",1,0,0},
        {"clear",0,0,0},
        {NULL,0,0,0}
    };

    int op,option_index = 0;
    string filename;
    while((op = getopt_long(argc,argv,"a:b",long_options,&option_index))!=-1){
        switch (op){
            case 0:
                switch(option_index){
                    case 0:
                        filename = optarg;
                        cout <<"filename is:" <<filename<<endl;
                        break;
                    case 1:
                        cout<<"clear is yes
";
                        break;
                    default:
                        cout<<"Please enter valid long option
";
                        break;
                }break;
        case 'a':
                if (is_option(optarg)) {
                    cout <<"-a option requires an argument" << endl;
                    optind -= 1; // put the option back into consideration for getopt_long()
                }
                else {
                    cout <<"a is set as" << optarg << endl;
                }
                break;
            case 'b':
                cout<<"b is set"<<endl;
                    break;
            default:
                cout<<"Please enter valid Arguments"<<endl;
                break;
        }
    }
    cout<<"

";

    return 0;
}

我希望改善此状况的一种方法是具有检查参数是否可能为选项的功能,而不是通过与getopt_long()相同的结构(long_options[]getopt_long()的字符串参数)进行查看。像我的快速n肮脏示例中那样对其进行硬编码。

实际上,由于这是我几个星期以来第二次遇到关于SO的问题(我找不到另一个),因此为getopt_long()和提供帮助者的朋友创建一个包装可能是值得的函数正是这样做的。也许我本周末晚些时候去做...