2008-09-10 106 views
38

如果您正在編寫可從命令行執行的程序,那麼您通常需要爲用戶提供幾個選項或標誌以及可能不止一個參數。我偶然發現了很多次,但是有什麼樣的設計模式可以循環使用參數並分離出合適的功能?處理命令行參數的設計模式是什麼

考慮:

myprogram -f filename -d directory -r regex 

你如何組織你的代碼檢索使用任何內置插件爲你的語言的參數後? (語言特定的答案歡迎,如果這有助於你清楚地說出答案)

+0

這應該被標記爲「語言不可知」,因爲問題是要求設計模式以及建議。 – martinatime 2008-09-10 15:52:53

回答

13

我不知道任何記錄的「模式」處理。

我相信處理參數最老的庫/ API之一是getopt。谷歌搜索「getopt」顯示了很多手冊頁和實現鏈接。

通常,我的應用程序中有一個首選項或設置服務,參數處理器知道如何與之通信。然後將參數翻譯成該服務中的應用程序,然後將其查詢。這可以像設置字典一樣簡單(如名爲「filename」的字符串設置)。

1

我會推薦使用命令行處理器庫。 Some Russian guy創造了一個體面的,但其中有噸。將節省您一些時間,以便您可以專注於應用程序的目的,而不是解析命令行開關!

+0

我喜歡這篇文章。謝謝! :-) – craigmoliver 2017-02-10 15:24:51

5

您沒有提到該語言,但對於我們所愛的Java,我們已經愛上了Apache Commons CLI。對於C/C++,getopt。

0

我使用Getopts::stdGetopts::long在Perl以及在C的Getopt函數此標準化了的參數的解析和格式。其他語言有不同的機制來處理這些。

希望這有助於

0

標準設計通常遵循的getopt做什麼,有許多語言,.NET,Python和C,Perl的,PHP等

的基本設計是getopt的圖書館有一個命令行解析器,它可以逐個返回循環中傳遞來檢查的參數。

This文章更詳細地討論了它。

2

boost::program_options庫是很好的。

+0

這是一個不錯的選擇。與舊的getopt相比,該庫有點複雜,但也允許使用配置文件(替換或集成命令行參數)。 – 2013-02-07 09:05:08

0

我對圖書館沒什麼興趣,但這絕對有幫助。作爲一個例子,我正在尋找更多的「僞代碼」來說明處理你的平均一堆標誌和一堆更長的參數的過程。

+0

你可能想在你的問題中更新這個,而不是在這裏澄清。它只是爲了答案。 – rpattabi 2008-09-21 16:38:29

2

假設你有一個「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; 
    } 
} 
2

我更喜歡「-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); 
    } 
4

幾點意見...

首先,雖然目前還沒有任何的模式本身,編寫解析器本質上是一種機械運動,因爲給定一個語法,解析器可以很容易地生成。想到像Bison和ANTLR這樣的工具。

這就是說,解析器生成器通常是命令行矯枉過正。所以通常的模式是自己寫一個(像其他人一樣)幾次,直到你厭倦了處理繁瑣的細節並找到一個圖書館來爲你做。

我寫了一個用於C++,節省了爲數衆多的getopt說明面授的努力,使好的使用模板:TCLAP

+0

``TCLAP``是一個非常棒的CLI解析庫。規則的預解析設置和解析argv後解析提取非常有用,直觀並有助於將程序分解爲正確的分立組件(恕我直言)。 – Sean 2013-01-21 07:08:14

2

我riffing由mes5k的ANTLR答案。這個link to Codeproject用於討論ANLTR並使用訪問模式來實現您希望應用採取的操作的文章。它寫得很好,值得回顧。

12

我認爲下面的答案是沿的線條更是你正在尋找:

你應該看看應用模板模式(模板方法「設計模式」 [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

3

那麼,它的舊帖子,但我仍然想貢獻。這個問題的目的是選擇設計模式,但我可以看到關於使用哪個庫的許多討論。我已經檢查了微軟鏈接,根據lindsay談論模板設計模式使用。

但是,我不相信這個帖子。模板模式的意圖是定義一個模板,這個模板將被各種其他類實現以具有統一的行爲。我不認爲解析命令行適合它。

我寧願去用「Command」設計模式。這種模式最適合菜單驅動的選項。

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

所以在你的情況,-f,-d和-R所有成爲具有定義共同的或單獨的接收器的命令。這樣可以在將來定義更多的接收器。下一步將是鏈接這些命令的責任,以防需要處理鏈。我會選擇哪個。

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

我想這兩個的組合是最好的組織,爲命令行的處理或任何菜單驅動的方法的代碼。