Getopt shift optarg

2019-04-29 11:56发布

问题:

I need to call my program like this:

./program hello -r foo bar

I take hello out of argv[1], but i am having trouble with value bar, also should i change "r:" to something else?

while((c = getopt(argc, argv, "r:")) != -1){
   switch(i){
   ...
   case 'r':
     var_foo = optarg;
     //shell like argument shift here?
     var_bar = optarg;
     break;
...}

I know I could do this with passing through argv, but is there a way to do it with getopt similar way as in bash?

Thanks.

回答1:

bar is not an option argument in the eyes of getopt. Rather, GNU getopt rearranges the positional arguments so that at the end of the processing, you have argv[3] being "hello" and argv[4] being "bar". Basically, when you're done getopting, you still have positional arguments [optind, argc) to process:

int main(int argc, char * argv[])
{
     {
         int c;
         while ((c = getopt(argc, argv, ...)) != -1) { /* ... */ }
     }

     for (int i = optind; i != argc; ++i)
     {
         // have positional argument argv[i]
     }
}


回答2:

It depends on whether you're using GNU getopt() or not, and if you are, whether POSIXLY_CORRECT is set in the environment.

Classically (meaning non-GNU getopt()), all the option arguments must precede any non-option (file name) arguments. That would mean you have four non-option arguments.

If you have GNU getopt() and do not have POSIXLY_CORRECT set, then it will process option arguments anywhere on the command line. In that case, you'd have one option, -r with the argument value foo, and two non-option arguments (hello and bar).

To get Classic getopt() to recognize the -r, you'd have to require the first (non-option) argument and only then call getopt() at all:

int main(int argc, char **argv)
{
    char *cmd = argv[1];
    int   opt;

    argv[1] = argv[0];
    argv++;
    argc--;

    while ((opt = getopt(argv, argc, "r:")) != EOF)
    {
        switch (opt)
        {
        case 'r':
            ...capture optarg...
            break;
        default:
            ...report error....
            break;
        }
    }

    for (int i = optind; i < argc; i++)
        process_non_option_argument(cmd, argv[i]);

    return(0);
}

GNU getopt can also return non-option arguments if you enable it to do so. Other than that, the bar argument will always be treated as a non-option argument.



标签: c getopt