【问题标题】:Parsing multiple values for single option using argp in C在 C 中使用 argp 解析单个选项的多个值
【发布时间】:2015-12-26 08:33:27
【问题描述】:

我正在寻找一种使用argp 为单个选项传递多个参数的方法。 我想以这种方式调用我的命令行工具:

./foo -l user1 user2 user3 -name bar

在这里,我希望将 user1、user2 和 user3 作为参数传递给 -l 选项。由于 argp 每个选项只接受 1 个参数,我该如何实现呢?

目前,我有以下结构:

struct arguments arguments;
arguments.lists = "";
arguments.name = "";
argparse (&argp, argc, argv, 0, 0, &arguments);

因此,在正确解析选项 -l 后,argument.lists 应该是 "user1 user2 user3" 而不仅仅是 "user1"。 谢谢

【问题讨论】:

标签: c command-line-arguments


【解决方案1】:

不确定这是否是正确的方法,但我可以这样做:

if (strlen(arguments->lists) != 0) {
    char *temp;
    sprintf(temp, " %s", arg);
    strcat(arguments->lists, temp);
}
else {
    arguments->lists = arg;
}

这样,如果为选项 -l--lists 传递了一个额外的参数,它会根据需要附加。

【讨论】:

    【解决方案2】:

    参数在argv[] 数组中的显示方式取决于所使用的命令外壳。大多数命令 shell 遵循普遍接受的标准,即命令行参数用空格分隔,如果你想用空格指定参数,则必须用引号引起来。

    所以./foo -l user1 user2 user3 -name foo是一个命令行,它将作为七个参数提供给C运行时,第一个是程序的名称,其余六个参数是-luser1user2user3-namefoo

    如果您在命令行输入./foo -l "user1 user2 user3" -name foo,其中用户列表(user1、user2 和 user3)位于带引号的字符串中,则命令行将作为五个参数提供给 C 运行时,第一个是程序的名称,其余四个参数分别为-luser1 user2 user3(引号通常被命令外壳删除并且都在同一个参数中)、-namefoo

    回到过去的 UNIX C 命令行实用程序,我们会为简单的命令行解析执行以下操作。以下源代码完成了命令行类可能完成的工作。这是使用 C++ 完成的,但采用 C 风格。

    当然,因为这是放在一起的,所以它不是很健壮,例如,特定命令行选项的 30 多个参数会导致问题。

    // arglist.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <iostream>
    
    /*
     *  argument options accepted are as follows:
     *    -l  -> indicates a user list of one or more user names follows
     *    -name  -> indicates a name for the list follows
     *
     *  arguments without a leading dash are considered to be option changes
     *  and arguments without a leading dash are considered to be arguments
     *  for the last option.
    **/
    typedef struct {
        int  index;
        int  argListIndex[30];
    } argList;
    
    const int indexOptionUnknown = 0;
    const int indexOptionL = 1;
    const int indexOptionName = 2;
    
    int main(int argc, char * argv[])
    {
        // the index into the argv[] array. zeroth element of argve[] is ignored.
        argList myList[3] = {0};
        int     iMyList = 0;
    
        // we skip the first argument which is the name of our program
        // we then process the remaining command line arguments which the C runtime
        // has provided as a series of char strings.
        for (int i = 1; i < argc; i++) {
            if (*argv[i] == '-') {
                // this is an argument option.  figure out which one.
                if (strcmp (argv[i], "-l") == 0) {
                    iMyList = indexOptionL;
                } else if (strcmp (argv[i], "-name") == 0) {
                    iMyList = indexOptionName;
                } else {
                    // unknown option so we will ignore it.
                    iMyList = indexOptionUnknown;
                }
            } else {
                // this is an argument for the last option found
                if (iMyList > indexOptionUnknown) {
                    myList[iMyList].argListIndex[ myList[iMyList].index ]  = i;
                    myList[iMyList].index++;
                }
            }
        }
    
        std::cout << "option -l, count of arguments " << myList[indexOptionL].index << std::endl;
        for (int i = 0; i < myList[indexOptionL].index; i++) {
            std::cout << "   " << i << " is " << argv[myList[indexOptionL].argListIndex[i]] << std::endl;
        }
    
        std::cout << "option -name, count of arguments " << myList[indexOptionName].index << std::endl;
        for (int i = 0; i < myList[indexOptionName].index; i++) {
            std::cout << "   " << i << " is " << argv[myList[indexOptionName].argListIndex[i]] << std::endl;
        }
    
        return 0;
    }
    

    pgm -l user1 user2 user3 -name foo 等参数行的输出是:

    option -l, count of arguments 3
       0 is user1
       1 is user2
       2 is user3
    option -name, count of arguments 1
       0 is foo
    

    pgm -l user1 -l user2 -l user3 -name foo 这样的命令行将是相同的输出。该解析器所做的是在命令行上为特定选项构建参数列表。

    如果提供了pgm -l "user1 user2 user3" -name foo 等命令行,则输出会因引用的参数而改变,结果为:

    option -l, count of arguments 1
       0 is user1  user2 user3
    option -name, count of arguments 1
       0 is foo
    

    【讨论】:

    • 谢谢,这很有用。但是,我真的很想使用 argp,因为它有内置代码来显示选项用法和其他检查。
    【解决方案3】:

    命令行上的标准语法是:

    ./foo -l user1 -l user2 -l user3 -name bar
    

    大多数命令行解析库都会理解这一点。

    【讨论】:

    • 嗨,我试过了,但选项 (-l) 被最后一个已知选项覆盖。不知道为什么。
    • 我明白了。在这种情况下,要支持最标准的语法,您可能需要使用不同的解析器,例如旧的 getopt,这使得支持上述内容变得简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-18
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-23
    • 2012-06-01
    相关资源
    最近更新 更多