代码之家  ›  专栏  ›  技术社区  ›  Sam McAfee

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

  •  42
  • Sam McAfee  · 技术社区  · 16 年前

    如果您正在编写一个可从命令行执行的程序,您通常希望为用户提供几个选项或标志,以及可能不止一个参数。我曾多次遇到这种情况,但是否有某种设计模式可以循环遍历参数并调用适当的处理程序函数?

    考虑:

    myprogram -f filename -d directory -r regex
    

    在使用语言的任何内置项检索参数后,如何组织处理程序函数?(欢迎使用特定语言的答案,如果这有助于您清楚表达答案)

    16 回复  |  直到 6 年前
        1
  •  13
  •   Peter Ritchie    16 年前

    我不知道用于处理的任何文档化的“模式”。

    我相信处理参数的最古老的库/API之一是getopt。谷歌“getopt”显示了许多手册页和到实现的链接。

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

        2
  •  13
  •   Lindsay Morsillo    13 年前

    我认为下面的答案更符合你想要的:

    您应该考虑应用模板模式(在“设计模式”中的模板方法[gamma,el al])

    简而言之,整个过程如下:

    If the arguments to the program are valid then
        Do necessary pre-processing
        For every line in the input
            Do necessary input processing
        Do necessary post-processing
    Otherwise
        Show the user a friendly usage message
    

    简而言之,实现一个consoleEngineBase类,该类具有以下方法:

    PreProcess()
    ProcessLine()
    PostProcess()
    Usage()
    Main()
    

    然后创建一个机箱,它实例化一个consoleengine()实例,并发送main()消息来启动它。

    要查看如何将此应用于控制台或命令行程序的良好示例,请查看以下链接: http://msdn.microsoft.com/en-us/magazine/cc164014.aspx

    这个例子在C中,但是思想很容易在任何其他环境中实现。

    您可以将getopt()看作是适合于参数处理(预处理)的部分。

    希望这有帮助。

        3
  •  5
  •   Jason Cohen    16 年前

    你没有提到语言,但是我们已经爱上了Java Apache Commons CLI . 对于C/C++,GETOPT。

        4
  •  4
  •   Sean    11 年前

    关于这个的一些评论…

    首先,虽然本身没有任何模式,但是编写解析器本质上是一个机械的练习,因为给定了语法,解析器就可以很容易地生成。像野牛和鹿角这样的工具浮现在脑海中。

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

    我为C++写了一篇文章,它节省了大量的GETOPT,并很好地使用了模板: TCLAP

        5
  •  4
  •   amarnath chatterjee    10 年前

    嗯,这是一个旧职位,但我仍然想贡献。这个问题是关于设计模式的选择,但是我可以看到很多关于使用哪个库的讨论。我已经按照Lindsay的说法查看了微软的链接,它讨论了要使用的模板设计模式。

    但是,我不相信这个职位。模板模式的目的是定义一个模板,该模板将由不同的其他类实现,以具有统一的行为。我认为解析命令行不适合它。

    我宁愿选择“命令”设计模式。此模式最适合菜单驱动的选项。

    http://www.blackwasp.co.uk/Command.aspx

    所以在您的例子中,-f、-d和-r都成为定义了公共或独立接收器的命令。这样,将来可以定义更多的接收器。下一步将是链接这些命令的职责,以防需要处理链。我会选择的。

    http://www.blackwasp.co.uk/ChainOfResponsibility.aspx

    我想这两种方法的组合最适合组织用于命令行处理或任何菜单驱动方法的代码。

        6
  •  2
  •   argv0    16 年前

    这个 boost::program_options 如果你在C++中,并且使用Boost的话,图书馆是很好的。

        7
  •  2
  •   Vinko Vrsalovic    16 年前

    假设您有一个“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;
        }
    }
    
        8
  •  2
  •   Martin Del Vecchio    16 年前

    我更喜欢“-t-text”和“-i 44”这样的选项;我不喜欢“-fname”或“-very long argument=someone-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);
       }
    
        9
  •  2
  •   David Robbins    16 年前

    我正在用5公里的速度搜索安特尔的答案。这个 link to Codeproject 是一篇讨论ANLTR并使用访问模式来实现您希望应用程序采取的操作的文章。它写得很好,值得一看。

        10
  •  1
  •   Kilhoffer Guffa    16 年前

    我建议使用命令行处理器库。 Some Russian guy 创造了一个体面的,但有很多。将为您节省一些时间,这样您就可以专注于应用程序的目的,而不是分析命令行开关!

        11
  •  1
  •   cfeduke    16 年前
        12
  •  1
  •   Meadock    8 年前
        13
  •  0
  •   sabiland    16 年前

    您没有为此提到语言,但是如果您正在寻找一个非常好的关于getopt的objective-c包装,那么Dave Dribin的ddcli框架非常好。

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

        14
  •  0
  •   Xetius    16 年前

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

    希望这有帮助

        15
  •  0
  •   Vinko Vrsalovic    16 年前

    标准设计通常遵循getopt的功能,有许多语言的getopt库,.net、python、c、perl、php等。

    基本设计是有一个命令行解析器,它一部分一部分地返回传递给循环中检查的参数。

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

        16
  •  0
  •   Sam McAfee    16 年前

    我对图书馆不太感兴趣,尽管这绝对有帮助。我在寻找一些“伪代码”,以说明如何处理say-your-average一堆标志和一堆更长的参数为例。