2009-06-27 61 views
37

在C中,getopt_long不解析命令行參數參數的可選參數。getopt不解析參數的可選參數

當我運行該程序時,可選參數不被識別,如下面的示例運行。

$ ./respond --praise John 
Kudos to John 
$ ./respond --blame John 
You suck ! 
$ ./respond --blame 
You suck ! 

這裏是測試代碼。

#include <stdio.h> 
#include <getopt.h> 

int main(int argc, char ** argv) 
{ 
    int getopt_ret, option_index; 
    static struct option long_options[] = { 
       {"praise", required_argument, 0, 'p'}, 
       {"blame", optional_argument, 0, 'b'}, 
       {0, 0, 0, 0}  }; 
    while (1) { 
     getopt_ret = getopt_long(argc, argv, "p:b::", 
            long_options, &option_index); 
     if (getopt_ret == -1) break; 

     switch(getopt_ret) 
     { 
      case 0: break; 
      case 'p': 
       printf("Kudos to %s\n", optarg); break; 
      case 'b': 
       printf("You suck "); 
       if (optarg) 
        printf (", %s!\n", optarg); 
       else 
        printf ("!\n", optarg); 
       break; 
      case '?': 
       printf("Unknown option\n"); break; 
     } 
    } 
    return 0; 
} 
+2

我在這裏回答了這個問題,所以其他人不需要把頭靠在牆上。 – hayalci 2009-06-27 12:38:01

回答

76

雖然glibc的文檔或getopt的手冊頁中未提到,可選參數長風格的命令行參數要求「等號」(=)。將可選參數與參數分開的空格不起作用。

與測試代碼運行的一個例子:

$ ./respond --praise John 
Kudos to John 
$ ./respond --praise=John 
Kudos to John 
$ ./respond --blame John 
You suck ! 
$ ./respond --blame=John 
You suck , John! 
+1

請注意,Perl的Getopt :: Long模塊不具有相同的要求。 Boost.Program_options會。 – 2009-06-27 15:08:45

+9

哇,這很糟糕。我遇到了與常規getopt()相同的問題,並且在使用optstring「a ::」時,只有在選項和參數之間具有零空格時纔會設置optarg,如'-afoo' – SiegeX 2009-11-20 23:44:10

+2

剛剛碰到了這個,但是現在在getopt中提到了這一點。 – abc 2012-02-05 21:48:52

1

我也遇到了同樣的問題,來到了這裏。然後我意識到這一點。 你沒有太多的「optional_argument」用例。如果需要某個選項,請從程序邏輯中檢查,如果某個選項是可選的,則不需要執行任何操作,因爲在getopt級別,所有選項都是可選的,它們不是必需的,因此沒有使用「optional_argument」的用例。希望這可以幫助。

PS:對於上面的例子,我認爲正確的選項是 --praise --praise名「名」 --blame --blame名「名」

7

手冊頁肯定不會非常好的文檔,但源代碼有一點幫助。

簡單地說:你應該這樣做下面的(雖然這可能有點過分迂腐):

if( !optarg 
    && optind < argc // make sure optind is valid 
    && NULL != argv[optind] // make sure it's not a null string 
    && '\0' != argv[optind][0] // ... or an empty string 
    && '-' != argv[optind][0] // ... or another option 
) { 
    // update optind so the next getopt_long invocation skips argv[optind] 
    my_optarg = argv[optind++]; 
} 
/* ... */ 

從前面_getopt_internal的評論中:

..

如果getopt找到另一個選項字符,則返回該字符 更新optindnextchar,以便下次調用getopt可以 使用以下選項字符或ARGV元素恢復掃描。

如果沒有更多選項字符,則getopt返回-1。 然後optind是第一個ARGV元素 的ARGV中的索引,這不是一個選項。 (該ARGV元素已經被置換 ,使那些現在沒有最後來選擇。)<-- a note from me: if the 3rd argument to getopt_long starts with a dash, argv will not be permuted

...

如果OPTSTRING一個char後跟一個冒號,這意味着它想要的ARG , ,因此在optarg中返回相同ARGV元素中的以下文本或以下 ARGV元素的文本。兩個冒號表示 想要一個可選的arg選項;如果在當前ARGV元素中有文本, 它在optarg,中返回,否則optarg設置爲零

...

...雖然你要做的字裏行間讀點書。以下是你想要的:

#include <stdio.h> 
#include <getopt.h> 

int main(int argc, char* argv[]) { 
    int getopt_ret; 
    int option_index; 
    static struct option long_options[] = { 
     {"praise", required_argument, 0, 'p'} 
    , {"blame", optional_argument, 0, 'b'} 
    , {0, 0, 0, 0} 
    }; 

    while(-1 != (getopt_ret = getopt_long( argc 
              , argv 
              , "p:b::" 
              , long_options 
              , &option_index))) { 
    const char *tmp_optarg = optarg; 
    switch(getopt_ret) { 
     case 0: break; 
     case 1: 
     // handle non-option arguments here if you put a `-` 
     // at the beginning of getopt_long's 3rd argument 
     break; 
     case 'p': 
     printf("Kudos to %s\n", optarg); break; 
     case 'b': 
     if( !optarg 
      && NULL != argv[optindex] 
      && '-' != argv[optindex][0]) { 
      // This is what makes it work; if `optarg` isn't set 
      // and argv[optindex] doesn't look like another option, 
      // then assume it's our parameter and overtly modify optindex 
      // to compensate. 
      // 
      // I'm not terribly fond of how this is done in the getopt 
      // API, but if you look at the man page it documents the 
      // existence of `optarg`, `optindex`, etc, and they're 
      // not marked const -- implying they expect and intend you 
      // to modify them if needed. 
      tmp_optarg = argv[optindex++]; 
     } 
     printf("You suck"); 
     if (tmp_optarg) { 
      printf (", %s!\n", tmp_optarg); 
     } else { 
      printf ("!\n"); 
     } 
     break; 
     case '?': 
     printf("Unknown option\n"); 
     break; 
     default: 
     printf("Unknown: getopt_ret == %d\n", getopt_ret); 
     break; 
    } 
    } 
    return 0; 
} 
-3

如果你寫參數旁邊的參數沒有空格字符不等於也可以。例如:

$ ./respond --blameJohn 
You suck John!