处理命令行参数的设计模式是什么

时间:2020-03-05 18:50:49  来源:igfitidea点击:

如果要编写可从命令行执行的程序,则通常要向用户提供几个选项或者标志以及可能不止一个参数。我已经无数次地迷失了自己的方式,但是是否存在某种用于遍历args并调用适当的处理函数的设计模式?

考虑:

myprogram -f filename -d directory -r regex

使用适用于语言的内置函数检索参数后,如何组织处理程序函数? (欢迎使用针对特定语言的答案,如果可以明确说明答案)

解决方案

回答

我不知道要处理任何记录的"模式"。

我相信用于处理参数的最古老的库/ API之一是getopt。谷歌搜索" getopt"显示了许多手册页以及实现的链接。

通常,我的应用程序中有一个首选项或者设置服务,参数处理器知道如何与之通信。然后将参数转换为该服务中的某个内容,然后由应用程序进行查询。这可以像设置字典一样简单(例如,名为"文件名"的字符串设置)。

回答

我建议使用命令行处理器库。一些俄罗斯人创造了一个像样的人,但那里有很多人。这将节省我们一些时间,因此我们可以专注于应用程序的用途,而不用解析命令行开关!

回答

我们没有提到该语言,但是对于Java,我们喜欢Apache Commons CLI。对于C / C ++,请使用getopt。

回答

我们没有提到这种语言,但是如果我们正在寻找一个围绕getopt的非常好的Objective-C包装器,那么Dave Dribin的DDCLI框架就非常不错。

http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli

回答

我在perl中使用Getopts :: std和Getopts :: long,在C语言中也使用Getopt函数。这标准化了参数的解析和格式。其他语言具有处理这些问题的不同机制。

希望这可以帮助

回答

标准设计通常遵循getopt所做的事情,有针对多种语言的getopt库,包括.NET,python,C,Perl,PHP等。

基本设计是具有一个命令行解析器,该解析器将部分返回循环传递的要检查的参数。

本文将对其进行更详细的讨论。

回答

Getopt是唯一的方法。

http://sourceforge.net/projects/csharpoptparse

回答

如果我们使用的是C ++并且可以轻松使用Boost,则boost :: program_options库非常有用。

回答

我对库的兴趣不大,但这绝对有帮助。我一直在寻找一些"伪代码",以举例说明我们处理平均一堆标志和一堆更长的参数的过程。

回答

假设我们有一个旨在使用标志进行设置的" config"对象和一个适当的命令行解析器,该解析器负责解析命令行并提供恒定的选项流,下面是一个伪代码块

while (current_argument = cli_parser_next()) {
    switch(current_argument) {
        case "f": //Parser strips the dashes
        case "force":
            config->force = true;
            break;
        case "d":
        case "delete":
            config->delete = true;
            break;
        //So on and so forth
        default:
            printUsage();
            exit;
    }
}

回答

我更喜欢" -t text"和" -i 44"之类的选项;我不喜欢" -fname"或者" --very-long-argument = some_value"。

而"-?","-h"和" / h"都将显示帮助屏幕。

这是我的代码的外观:

int main (int argc, char *argv[])
   {  int i;
      char *Arg;
      int ParamX, ParamY;
      char *Text, *Primary;

   // Initialize...
   ParamX = 1;
   ParamY = 0;
   Text = NULL;
   Primary = NULL;

   // For each argument...
   for (i = 0; i < argc; i++)
      {
      // Get the next argument and see what it is
      Arg = argv[i];
      switch (Arg[0])
         {
         case '-':
         case '/':
            // It's an argument; which one?
            switch (Arg[1])
               {
               case '?':
               case 'h':
               case 'H':
                  // A cry for help
                  printf ("Usage:  whatever...\n\n");
                  return (0);
                  break;

               case 't':
               case 'T':
                  // Param T requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // Just remember this
                  Text = Arg;

                  break;

               case 'x':
               case 'X':
                  // Param X requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // The value is there; get it and convert it to an int (1..10)
                  Arg = argv[i];
                  ParamX = atoi (Arg);
                  if ((ParamX == 0) || (ParamX > 10))
                     {
                     printf ("Error:  invalid value for '%s'; must be between 1 and 10.\n\n", Arg);
                     return (1);
                     }

                  break;

               case 'y':
               case 'Y':
                  // Param Y doesn't expect a value after it
                  ParamY = 1;
                  break;

               default:
                  // Unexpected argument
                  printf ("Error:  unexpected parameter '%s'; type 'command -?' for help.\n\n", Arg);
                  return (1);
                  break;
               }

            break;

         default:
            // It's not a switch that begins with '-' or '/', so it's the primary option
            Primary = Arg;

            break;
         }
      }

   // Done
   return (0);
   }

回答

关于此的一些评论...

首先,虽然本身没有任何模式,但是编写解析器本质上是一项机械练习,因为给定语法,可以轻松生成解析器。我想到了Bison和ANTLR等工具。

也就是说,解析器生成器通常对于命令行来说是多余的。因此,通常的模式是自己写几次(如其他人所展示的),直到我们厌倦了处理繁琐的细节并找到一个库来为我们做。

我为C ++编写了一个代码,它节省了getopt付出的大量工作并很好地利用了模板:TCLAP

回答

我正在通过mes5k仔细研究ANTLR的答案。该指向Codeproject的链接是用于讨论ANLTR以及如何使用访问模式来实现我们希望应用执行的操作的文章。它写得很好,值得回顾。