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

问题描述:

如果您正在编写可从命令行执行的程序,那么您通常需要为用户提供几个选项或标志以及可能不止一个参数。我偶然发现了很多次,但是有什么样的设计模式可以循环使用参数并分离出合适的功能?处理命令行参数的设计模式是什么

考虑:

myprogram -f filename -d directory -r regex 

你如何组织你的代码检索使用任何内置插件为你的语言的参数后? (语言特定的答案欢迎,如果这有助于你清楚地说出答案)

+0

这应该被标记为“语言不可知”,因为问题是要求设计模式以及建议。 – martinatime 2008-09-10 15:52:53

我不知道任何记录的“模式”处理。

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

通常,我的应用程序中有一个首选项或设置服务,参数处理器知道如何与之通信。然后将参数翻译成该服务中的应用程序,然后将其查询。这可以像设置字典一样简单(如名为“filename”的字符串设置)。

我会推荐使用命令行处理器库。 Some Russian guy创造了一个体面的,但其中有吨。将节省您一些时间,以便您可以专注于应用程序的目的,而不是解析命令行开关!

+0

我喜欢这篇文章。谢谢! :-) – craigmoliver 2017-02-10 15:24:51

您没有提到该语言,但对于我们所爱的Java,我们已经爱上了Apache Commons CLI。对于C/C++,getopt。

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

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

我使用Getopts::stdGetopts::long在Perl以及在C的Getopt函数此标准化了的参数的解析和格式。其他语言有不同的机制来处理这些。

希望这有助于

标准设计通常遵循的getopt做什么,有许多语言,.NET,Python和C,Perl的,PHP等

的基本设计是getopt的图书馆有一个命令行解析器,它可以逐个返回循环中传递来检查的参数。

This文章更详细地讨论了它。

Getopt是唯一的出路。如果你在C++,并有使用Boost的豪华

http://sourceforge.net/projects/csharpoptparse

boost::program_options库是很好的。

+0

这是一个不错的选择。与旧的getopt相比,该库有点复杂,但也允许使用配置文件(替换或集成命令行参数)。 – 2013-02-07 09:05:08

我对图书馆没什么兴趣,但这绝对有帮助。作为一个例子,我正在寻找更多的“伪代码”来说明处理你的平均一堆标志和一堆更长的参数的过程。

+0

你可能想在你的问题中更新这个,而不是在这里澄清。它只是为了答案。 – rpattabi 2008-09-21 16:38:29

假设你有一个“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

+0

``TCLAP``是一个非常棒的CLI解析库。规则的预解析设置和解析argv后解析提取非常有用,直观并有助于将程序分解为正确的分立组件(恕我直言)。 – Sean 2013-01-21 07:08:14

我riffing由mes5k的ANTLR答案。这个link to Codeproject用于讨论ANLTR并使用访问模式来实现您希望应用采取的操作的文章。它写得很好,值得回顾。

我认为下面的答案是沿的线条更是你正在寻找:

你应该看看应用模板模式(模板方法“设计模式” [Gamma值,等人])

总之它的整体处理看起来是这样的:

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()看作适合参数处理(预处理)的部分。

希望这会有所帮助。

+1

upvoted坚持的概念,而不是执行。我觉得这应该是选择的答案。 – Plasmarob 2015-05-22 18:21:25

那么,它的旧帖子,但我仍然想贡献。这个问题的目的是选择设计模式,但我可以看到关于使用哪个库的许多讨论。我已经检查了微软链接,根据lindsay谈论模板设计模式使用。

但是,我不相信这个帖子。模板模式的意图是定义一个模板,这个模板将被各种其他类实现以具有统一的行为。我不认为解析命令行适合它。

我宁愿去用“Command”设计模式。这种模式最适合菜单驱动的选项。

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

所以在你的情况,-f,-d和-R所有成为具有定义共同的或单独的接收器的命令。这样可以在将来定义更多的接收器。下一步将是链接这些命令的责任,以防需要处理链。我会选择哪个。

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

我想这两个的组合是最好的组织,为命令行的处理或任何菜单驱动的方法的代码。