getopt_long() - 正确使用它的方法?

时间:2022-09-06 14:04:50

OK, I have searched and found the following two * topics that started me in the right direction:

好的,我搜索过并发现以下两个*主题让我朝着正确的方向前进:

Argument-parsing helpers for C/UNIX

C / UNIX的参数解析助手

Pass arguments into C program from command line

从命令行将参数传递给C程序

NOTE: ALL CODE IS PSEUDO-CODE. WILL POST COMPILABLE CODE WHEN IT WORKS.

注意:所有代码都是PSEUDO-CODE。将在其工作时发布可编译代码。

However, I'm still completely confused on how to use getopt_long() in C. The program I'm writing is defined as having the following possible tags (but can include as many as you absolutely need, filling the rest in with empty values):

但是,我仍然对如何在C中使用getopt_long()感到困惑。我正在编写的程序被定义为具有以下可能的标记(但可以包含您绝对需要的数量,其余用空值填充) ):

id3tagEd filename -title "title" -artist "artist" -year 1991 -comment "comment" -album "album" -track 1

Now, from what I read, I need to utilize a struct for the long options, correct? If so, I wrote something along the lines of this:

现在,根据我的阅读,我需要利用一个结构来获取长期选项,对吗?如果是这样,我写了一些类似的东西:

struct fields field =
{
    char *[] title;
    char *[] artist;
    char *[] album;
    int year;
    char *[] comment;
    int track;
}


static struct options long_options[] =
{
    {"title", 0, &field.title, 't'},
    {"artist", 0, &field.artist, 'a'},
    {"album", 0, &field.album, 'b'},
    {"year", 0, &field.year, 'y'},
    {"comment", 0, &field.comment, 'c'},
    {"track", 0, &field.track, 'u'},
    {0, 0, 0, 0}
}

Now, from what I gathered, I would be calling it via this:

现在,根据我收集的内容,我将通过以下方式调用它:

int option_index = 0;

int values = getopt_long(argc, argv, "tabycu", long_options, &option_index);

From here, could I strictly use the field struct and do what I need to within my program? However, if this is the case, can someone explain the whole long_options struct? I read the man pages and such, and I'm just utterly confused. By rereading the man pages, I can see I can set variables to null, and should be setting all my option requirements to "required_argument"? And then setting the structs via a while() loop? However, I see optarg being used. Is this set by getopt_long()? Or is it missing from the example?

从这里开始,我可以严格使用字段结构并在程序中执行我需要的操作吗?但是,如果是这种情况,有人可以解释整个long_options结构吗?我阅读了这些手册页,我只是完全糊涂了。通过重读手册页,我可以看到我可以将变量设置为null,并且应该将所有选项要求设置为“required_argument”?然后通过while()循环设置结构?但是,我看到正在使用optarg。这是由getopt_long()设置的吗?或者是否从示例中遗漏了?

And one last issue, I will always have an unnamed required option: filename, would I just use argv[0] to gain access to that? (Since I can assume it'll be first).

最后一个问题,我将始终有一个未命名的必需选项:filename,我只是使用argv [0]来获取访问权限吗? (因为我可以假设它将是第一个)。

On a side note, this is related to a homework problem, but it has nothing to do with fixing it, its more of a fundamental, have to understand argument passing and parsing in C via command line first.

在旁注中,这与作业问题有关,但它与修复它无关,它更多的是基础,必须首先通过命令行理解参数传递和解析。

2 个解决方案

#1


23  

First off, you probably don't want 0 for the has_arg field - it must be one of no_argument, required_arguemnt, or optional_argument. In your case, all of them are going to be required_argument. Besides that, you're not using the flag field correctly - it has to be an integer pointer. If the corresponding flag is set, getopt_long() will fill it in with the integer you passed in via the val field. I don't think you need this feature at all. Here's a better (shortened) example for your case:

首先,你可能不希望has_arg字段为0 - 它必须是no_argument,required_arguemnt或optional_argument之一。在您的情况下,所有这些都将是required_argument。除此之外,你没有正确使用标志字段 - 它必须是一个整数指针。如果设置了相应的标志,getopt_long()将使用通过val字段传入的整数填充它。我认为你根本不需要这个功能。这是一个更好(缩短)的例子:

static struct option long_options[] =
{
    {"title", required_argument, NULL, 't'},
    {"artist", required_argument, NULL, 'a'},
    {NULL, 0, NULL, 0}
};

Then later, you can use it appropriately (straight from the manpage, I added some comments):

然后,您可以适当地使用它(直接从联机帮助页,我添加了一些注释):

// loop over all of the options
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1)
{
    // check to see if a single character or long option came through
    switch (ch)
    {
         // short option 't'
         case 't':
             field.title = optarg; // or copy it if you want to
             break;
         // short option 'a'
         case 'a':
             field.artist = optarg; // or copy it if you want to
             break;
    }
}

You can extend for your other fields as necessary (and add some error handling, please!). Note - if you want to use -title and -artist like you have in your example, you'll need to use getopt_long_only(), which doesn't have short options.

您可以根据需要扩展其他字段(并添加一些错误处理,请!)。注意 - 如果你想在你的例子中使用-title和-artist,你需要使用getopt_long_only(),它没有短选项。

As to your filename option, you'll get that out as a '?' from the getopt_long() call, so you could handle it at that time. Your other options are to require that it is either the first or the last option and handle it by itself separately.

至于你的文件名选项,你会把它作为'?'从getopt_long()调用,所以你可以在那时处理它。您的其他选择是要求它是第一个或最后一个选项并单独处理它。

#2


5  

If you use the popt library, you will be able to create something smart as you did in your pseudo-code:

如果您使用popt库,您将能够像在伪代码中一样创建智能:

#include <stdio.h>
#include "popt.h"

struct _field {
    char *title;
    char *artist;
    /* etc */
} field;

field.title = NULL;
field.artist = NULL;

/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */
struct poptOption optionsTable[] = {

   {"title", 't', POPT_ARG_STRING, &field.title, 't'
    "set the 'title' of the album" },
   {"artist", 'a', POPT_ARG_STRING, &field.artist, 'a'
    "set the 'artist' of the album" },
   POPT_AUTOHELP
   POPT_TABLEEND
};

poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]");

char c;
while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
        case 't':
            /* do extra stuff only if you need */
            break;
        case 'a':
            /* do extra stuff only if you need */
            break;
        default:
            poptPrintUsage(optCon, stderr, 0);
            exit(1);
    }
}

if (field.title) printf("\nTitle is [%s]", field.title);
if (field.artist) printf("\nArtist is [%s]", field.artist)

Be smart than getopt ;)

比getopt聪明;)

#1


23  

First off, you probably don't want 0 for the has_arg field - it must be one of no_argument, required_arguemnt, or optional_argument. In your case, all of them are going to be required_argument. Besides that, you're not using the flag field correctly - it has to be an integer pointer. If the corresponding flag is set, getopt_long() will fill it in with the integer you passed in via the val field. I don't think you need this feature at all. Here's a better (shortened) example for your case:

首先,你可能不希望has_arg字段为0 - 它必须是no_argument,required_arguemnt或optional_argument之一。在您的情况下,所有这些都将是required_argument。除此之外,你没有正确使用标志字段 - 它必须是一个整数指针。如果设置了相应的标志,getopt_long()将使用通过val字段传入的整数填充它。我认为你根本不需要这个功能。这是一个更好(缩短)的例子:

static struct option long_options[] =
{
    {"title", required_argument, NULL, 't'},
    {"artist", required_argument, NULL, 'a'},
    {NULL, 0, NULL, 0}
};

Then later, you can use it appropriately (straight from the manpage, I added some comments):

然后,您可以适当地使用它(直接从联机帮助页,我添加了一些注释):

// loop over all of the options
while ((ch = getopt_long(argc, argv, "t:a:", long_options, NULL)) != -1)
{
    // check to see if a single character or long option came through
    switch (ch)
    {
         // short option 't'
         case 't':
             field.title = optarg; // or copy it if you want to
             break;
         // short option 'a'
         case 'a':
             field.artist = optarg; // or copy it if you want to
             break;
    }
}

You can extend for your other fields as necessary (and add some error handling, please!). Note - if you want to use -title and -artist like you have in your example, you'll need to use getopt_long_only(), which doesn't have short options.

您可以根据需要扩展其他字段(并添加一些错误处理,请!)。注意 - 如果你想在你的例子中使用-title和-artist,你需要使用getopt_long_only(),它没有短选项。

As to your filename option, you'll get that out as a '?' from the getopt_long() call, so you could handle it at that time. Your other options are to require that it is either the first or the last option and handle it by itself separately.

至于你的文件名选项,你会把它作为'?'从getopt_long()调用,所以你可以在那时处理它。您的其他选择是要求它是第一个或最后一个选项并单独处理它。

#2


5  

If you use the popt library, you will be able to create something smart as you did in your pseudo-code:

如果您使用popt库,您将能够像在伪代码中一样创建智能:

#include <stdio.h>
#include "popt.h"

struct _field {
    char *title;
    char *artist;
    /* etc */
} field;

field.title = NULL;
field.artist = NULL;

/* HERE IS WHAT YOU WANTED IN YOUR PSEUDO-CODE */
struct poptOption optionsTable[] = {

   {"title", 't', POPT_ARG_STRING, &field.title, 't'
    "set the 'title' of the album" },
   {"artist", 'a', POPT_ARG_STRING, &field.artist, 'a'
    "set the 'artist' of the album" },
   POPT_AUTOHELP
   POPT_TABLEEND
};

poptContext optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]");

char c;
while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
        case 't':
            /* do extra stuff only if you need */
            break;
        case 'a':
            /* do extra stuff only if you need */
            break;
        default:
            poptPrintUsage(optCon, stderr, 0);
            exit(1);
    }
}

if (field.title) printf("\nTitle is [%s]", field.title);
if (field.artist) printf("\nArtist is [%s]", field.artist)

Be smart than getopt ;)

比getopt聪明;)