2008-09-10 11 views
38

명령 줄에서 실행 가능한 프로그램을 작성하는 경우 사용자에게 여러 옵션 또는 플래그와 함께 둘 이상의 인수를 제공하려는 경우가 많습니다. 나는 여러 차례 내 길을 찾았지만, args를 반복하고 적절한 함수를 회전시키기위한 디자인 패턴이 있습니까?명령 줄 인수 처리를위한 디자인 패턴은 무엇입니까

고려 : 당신은 당신의 언어에 대한 어떤 내장 기능을 사용하여 인수를 검색 한 후

myprogram -f filename -d directory -r regex 

어떻게 코드를 구성합니까? (언어 별 답변을 환영합니다. 답을 명확히하는 데 도움이되는 경우)

+0

디자인 패턴과 제안 사항을 묻는 질문에 "언어에 구애받지 않는"태그를 사용해야합니다. – martinatime

답변

13

처리를 위해 문서화 된 "패턴"을 알지 못합니다.

인수를 처리하는 데있어 가장 오래된 라이브러리/API 중 하나가 getopt라고 생각합니다. Googling "getopt"는 많은 맨 페이지와 구현 링크를 보여줍니다.

일반적으로 내 응용 프로그램에는 인수 프로세서가 통신하는 방법을 알고있는 환경 설정 또는 설정 서비스가 있습니다. 그런 다음 인수는이 서비스에서 응용 프로그램이 제공하는 내용으로 변환됩니다. 이 설정은 사전 설정 ("filename"이라는 문자열 설정)과 같이 간단 할 수 있습니다.

1

명령 줄 프로세서 라이브러리를 사용하는 것이 좋습니다. Some Russian guy은 괜찮은 것을 만들었지 만 거기에는 수많은 톤이 있습니다. 명령 줄 스위치를 구문 분석하는 대신 앱의 목적에 집중할 수 있도록 시간을 절약 할 수 있습니다.

+0

이 기사가 마음에 들어요. 감사! :-) – craigmoliver

5

언어는 언급하지 않았지만 자바는 Apache Commons CLI을 좋아했습니다. C/C++의 경우 getopt.

0

는 펄에서 Getopts::stdGetopts::long를 사용하고, 또한 C.에서 Getopt 함수는이 매개 변수를 해석 및 포맷을 표준화합니다. 다른 언어는이를 처리하기위한 메커니즘이 다릅니다.

희망이 기본 설계가 인 많은 언어, .NET, 파이썬, C, 펄, PHP 등

에 대한 getopt는 라이브러리가, 표준 디자인은 일반적으로 getopt는이 무엇을 다음과

0

을하는 데 도움이 루프에서 검사 할 인수를 부분별로 반환하는 명령 줄 구문 분석기가 있습니다.

This 문서에서 자세히 설명합니다.

2

boost::program_options 라이브러리는 좋은 것입니다.

+0

좋은 선택입니다. 이 라이브러리는 구식 getopt에 비해 약간 복잡하지만 구성 파일 (명령 줄 인수 대체 또는 통합)을 사용할 수도 있습니다. –

0

나는 도서관에별로 관심이 없다. 그러나 확실히 도움이된다.예를 들어, 평균적인 플래그 묶음과 더 긴 인수를 말하는 처리를 보여주는 "의사 코드"를 더 찾고있었습니다.

+0

여기에 설명이 아니라 질문에이 내용을 업데이트 할 수 있습니다. 그것은 단지 답을 의미합니다. – rpattabi

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 같은 도구가 떠오른다.

즉, 파서 생성기는 대개 명령 행에 과도하게 사용됩니다. 그래서 일반적인 패턴은 당신이 지루한 세부 사항을 다룰 때까지 아플 때까지 당신 자신을 (다른 사람들이 시연했듯이) 몇 번 쓰고, 당신을 위해 그것을 할 도서관을 찾는 것입니다. 내가 mes5k으로 ANTLR 응답에 riffing있어 TCLAP

+0

''TCLAP''은 환상적인 CLI 파싱 라이브러리입니다. ''argv''의 파싱을 미리 파싱하고 규칙을 파싱하여 파싱하는 것은 매우 유용하고, 직관적이며 정확한 이산 컴포넌트 (IMHO)로 프로그램을 나눌 수 있습니다. – Sean

2

:

나는 부여를 getopt는 노력의 무리를 저장하고 템플릿의 좋은 사용합니다 C에 대한 하나 ++ 썼다. 이 link to Codeproject은 ANLTR에 대해 설명하고 방문 패턴을 사용하여 앱에서 취할 행동을 구현하는 기사를위한 것입니다. 그것은 잘 쓰여지고 검토 할만한 가치가 있습니다.

12

나는 다음과 같은 대답이의 라인을 따라 더 생각하는 당신을 위해 무엇을 찾고 있습니다 : 당신은 템플릿 패턴 적용 봐야한다

("디자인 패턴"에 템플릿 방법 [감마, 엘 알])

한마디로

그것의 전체 처리는 다음과 같습니다

,144 : 한마디로

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를 구현

그런 다음 ConsoleEngine() 인스턴스를 인스턴스화하고 Main() 메시지를 보내어 쫓아내는 섀시를 만듭니다.

는 다음 링크를 체크 아웃 콘솔이나 명령 줄 프로그램이 적용하는 방법의 좋은 예를 참조하십시오 : http://msdn.microsoft.com/en-us/magazine/cc164014.aspx

예는 C#에서입니다,하지만 아이디어는 쉽게 다른 환경에서 구현됩니다.

당신은 GetOpt()를 인자 처리 (전처리)에 적합하다고 생각할 것입니다.

희망이 도움이됩니다.

+1

은 구현이 아닌 개념을 고수하도록 권고 받았다. 나는 이것이 선택된 대답 이었음에 틀림 없어. – Plasmarob

3

음, 오래된 게시물이지만 여전히 기여하고 싶습니다.문제는 디자인 패턴의 선택에 관한 것이었지만 어떤 라이브러리를 사용할 지에 대한 많은 논의를 볼 수있었습니다. 내가 사용하는 템플릿 디자인 패턴에 대해 이야기 린지별로 마이크로 소프트 링크를 체크 아웃했습니다.

그러나 나는 그 게시물에 확신하지 못했습니다. 템플릿 패턴의 의도는 다양한 다른 클래스에 의해 구현되어 균일 한 동작을 갖는 템플릿을 정의하는 것입니다. 필자는 커맨드 라인을 구문 분석한다고 생각하지 않는다.

"Command"디자인 패턴을 사용하고 싶습니다. 이 패턴은 메뉴 구동 옵션에 가장 적합합니다.

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

-d 귀하의 경우, -f 너무

, 그리고 모든 -r 정의 공통 또는 별도의 수신기를 가지고 명령을하게된다. 그 방법으로 미래에 더 많은 수신기를 정의 할 수 있습니다. 다음 단계는 처리 체인이 필요한 경우 명령의 이러한 책임을 연결하는 것입니다. 내가 선택할 것이라고.

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

나는이 두 가지의 조합이 명령 행 처리 또는 메뉴 중심의 접근 방식에 대한 코드를 구성하는 것이 가장 적합합니다 같아요.