2009-06-27 15 views
37

W C, getopt_long nie analizuje opcjonalnych argumentów parametrów parametrów wiersza poleceń.getopt nie parsuje opcjonalnych argumentów do parametrów

Po uruchomieniu programu opcjonalny argument nie jest rozpoznawany, jak w przykładzie poniżej.

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

Oto kod testowy.

#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

Dokumentuję to tutaj z odpowiedzią, więc inni ludzie nie muszą uderzać głową o ścianę. – hayalci

Odpowiedz

76

Chociaż nie wymienione w dokumentacji glibc lub strony getopt mężczyzna, opcjonalne dla parametrów linii poleceń długo styl wymaga „znak równości” (=). Przestrzeń oddzielająca opcjonalny argument od parametru nie działa.

Przykładem uruchomić z kodem testu:

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

Pamiętaj, że moduł Getopt :: Long firmy Perl NIE ma takiego samego wymagania. Boost.Program_options ma. –

+9

Wow, to jest do bani. Wpadłem na ten sam problem ze zwykłym getopt() i przy użyciu optstring "a ::", optarg byłby ustawiony tylko jeśli masz ZERO spacji między opcją a argumentem takim jak "-afoo" – SiegeX

+2

Po prostu wpadł na to, ale to jest już wspomniane w man getopt. – abc

1

ja też wpadłem na ten sam problem i przyszedł tutaj. Wtedy to sobie uświadomiłem. Nie masz wiele przypadków użycia "optional_argument". Jeśli wymagana jest opcja, należy sprawdzić logikę programu, jeśli opcja jest opcjonalna, nie trzeba nic robić, ponieważ na poziomie getopt wszystkie opcje są opcjonalne, nie są obowiązkowe, więc nie ma przypadku użycia "opcjonalnego argumentu". Mam nadzieję że to pomoże.

ps: na powyższym przykładzie myślę poprawne opcje są --praise --praise-name "nazwa" --blame --blame-name "nazwa"

7

Strona człowiek na pewno nie dokumentuje to bardzo dobrze, ale kod źródłowy pomaga trochę.

skrócie: masz robić coś jak poniżej (choć może to być trochę zbyt pedantyczny):

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++]; 
} 
/* ... */ 

spośród poprzednich komentarzach _getopt_internal:

.. .

Jeśli getopt znajdzie inną postać funkcji, zwraca ten znak, aktualizowania optind i nextchar, aby następne wywołanie getopt mogło wznowić skanowanie za pomocą następującego znaku opcji lub elementu ARGV.

Jeśli nie ma więcej znaków opcji, getopt zwraca -1. Następnie optind jest indeksem w ARGV pierwszego elementu ARGV , który nie jest opcją. (Do ARGV-elementy zostały permutytu tak, że te, które nie są opcje teraz przychodzą ostatni.) <-- a note from me: if the 3rd argument to getopt_long starts with a dash, argv will not be permuted

...

Jeśli char w Optstring następuje dwukropek, to znaczy, że chce Arg , , więc następujący tekst w tym samym ARGV element lub tekst następującego ARGV element, jest zwracany w optarg.Dwa dwukropki oznaczają opcję, że chce opcjonalnego arg; jeśli tekst w bieżącym elemencie ARGV, , jest zwracany w optarg, w przeciwnym razie optarg jest ustawiony na zero.

...

... choć trzeba zrobić kilka czytania między wierszami. Oto, co chcesz:

#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; 
} 
+0

To zadziałało naprawdę dobrze, dzięki. Nie wiem, skąd masz optindex; nazywa się (extern int) optind dla mnie. – apanloco

+0

Wystąpił błąd w drugim przykładzie kodu, powinien to być 'optind' zamiast' optindex'. –

-3

Jeśli napiszesz argument obok parametru bez znaku spacji, żaden równy nie działa również. Na przykład:

$ ./respond --blameJohn 
You suck John! 
+0

To jest fałsz. './respond --blameJohn' ' ./odpowiedzi: nierozpoznana opcja '--blameJohn''' –

Powiązane problemy