当多头选项作为空头选项的参数给出时 - getopt_long

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

我正在学习如何使用 getopt_long 函数接受命令行参数,我做了 2 个长选项 'filename'(必需 arg)和 'clear'(无参数)和 2 个短参数'a'(带 arg)和 'b'(无 arg)当我执行时:

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

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

我的代码是:

#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\n";
                        break;
                    default:
                        cout<<"Please enter valid long option\n";
                        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<<"\n\n";

    return 0;
}

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

这是一个例子:

#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\n";
                        break;
                    default:
                        cout<<"Please enter valid long option\n";
                        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<<"\n\n";

    return 0;
}

我希望改进这一点的一种方法是拥有检查参数是否可能是一个选项的函数,即让它通过与 getopt_long() 相同的结构(long_options[]getopt_long()) 的字符串参数,而不是 hard-coding,就像我的 quick-n-dirty 示例中那样。

事实上,由于这是几周内我第二次在 SO 上遇到这个问题(我找不到另一个问题),为 [=13= 创建一个包装器可能是值得的] 和提供辅助功能的朋友正是这样做的。也许我会在本周末晚些时候继续努力...

我找到了更好的答案,这是我朋友告诉我的。

我可以直接使用 :: 而不是 : 这意味着 'a' 需要一个可选参数,所以 getopt_long 将检查 arg 是否是一个选项,如果没有 arg 或者 arg 是一个返回选项 0,我可以单独处理,如果 'a' 有非选项 arg,则情况正常处理。

最终代码为:

#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\n";
                        break;
                    default:
                        cout<<"Please enter valid long option\n";
                        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<<"\n\n";

    return 0;
}

这里不需要hard-coding任何东西。