2009-02-11 20 views
5

Czy ktoś może mi pomóc z funkcją getopt?biblioteka przetwarzania wiersza poleceń - getopt

Kiedy należy wykonać następujące czynności w głównym:

char *argv1[] = {"testexec","-?"}; 
char *argv2[] = {"testexec","-m","arg1"}; 
int cOption; 
/* test for -? */ 

setvbuf(stdout,(char*)NULL,_IONBF,0); 
printf("\n argv1 "); 
while ((cOption = getopt (2, argv1, "m:t:n:fs?")) != -1) { 
    switch(cOption){ 
     case 'm': 
      printf("\n -m Arg : %s \n",optarg); 
      break; 
     case '?': 
      printf("\n -? Arg "); 
      break; 
     case 'n': 
      printf("\n -n Arg : %s \n",optarg); 
      break; 
    } 
} 

printf("\n argv2 "); 

while ((cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) { 
    switch(cOption){ 
     case 'm': 
      printf("\n -m Arg : %s \n",optarg); 
      break; 
     case '?': 
      printf("\n -? Arg : %s \n",optarg); 
      break; 
     case 'n': 
      printf("\n -n Arg : %s \n",optarg); 
      break; 
    } 
} 
 

Używam tego kodu na rhel3 który wykorzystuje starą wersję libc. Nie wiem, który z nich jest dokładny.

Problem polega na tym, że getopt nie działa po raz drugi z argv2. Ale jeśli skomentuję pierwsze wywołanie getopt z argv1, to działa.

Czy ktoś może mi powiedzieć, co robię źle tutaj?

Odpowiedz

12

argv1 i 2 musi kończyć się 0:

char* argv1[] = {"par1", "par2", 0}; 

Edit: OK, czytam stronę getopt mężczyzna i znalazłem to:

Zmienna Optind jest indeks następny element do przetworzenia w argv. System inicjalizuje tę wartość na 1. Dzwoniący może zresetować ją do 1, aby ponownie rozpocząć skanowanie tego samego argumentu lub podczas skanowania nowego wektora argumentu.

Zatem, optind = 1 między dwoma wywołaniami getopt sprawia, że ​​działa on zgodnie z oczekiwaniami.

+0

Dobra odpowiedź, ale chociaż to prawda, spróbowałem zmienić ją w przykładowym kodzie i nie rozwiązałem konkretnego problemu, o który pytano. –

+0

David, masz rację. Właśnie zauważyłem ten błąd i zapomniałem o reszcie :) Poprawiłem odpowiedź, ponieważ zauważyłem, że jeśli zaktualizujesz wartość optind do 1, kod działa zgodnie z oczekiwaniami. Pozdrawiam: –

+2

Uwaga: standard POSIX nie stwierdza, że ​​zresetowanie optind do 1 zresetuje getopt() do stanu początkowego, szczególnie jeśli nie przeanalizowałeś całkowicie pierwszych argumentów. Na przykład, jeśli pierwszym argumentem jest -xy, a zatrzymasz się po przetworzeniu x, nie ma gwarancji, że reset optind działa. –

4

Funkcja getopt() wykorzystuje niektóre zmienne globalne, takie jak optind i optarg, do przechowywania informacji o stanie między połączeniami. Po zakończeniu przetwarzania jednego zestawu opcji w tych zmiennych pozostały dane, które powodują problemy z następnym zestawem opcji. Możesz spróbować zresetować stan getopt między wywołaniami, usuwając zmienne, ale nie jestem pewien, czy to zadziała, ponieważ funkcja może używać innych zmiennych, które nie są udokumentowane i nigdy nie wiesz, czy je uzyskałeś wszystko; poza tym byłaby to absolutnie nieprzenośna (to znaczy, gdyby zmiana getopt() uległa zmianie, twój kod zepsuje się). Szczegółowe informacje znajdują się w man page. Najlepiej nie używać getopt() dla więcej niż jednego zestawu argumentów w danym programie, jeśli możesz pomóc.

Nie jestem pewien, czy istnieje rzeczywista funkcja resetowania stanu getopt (lub być może nowa wersja funkcji, która pozwala przechowywać stan we własnych zmiennych) ... Wydaje mi się, że widzę coś takiego kiedyś, ale nie mogę go teraz znaleźć, gdybym wyglądał: -/

1

Czy istnieje jakiś powód, dla którego nie używasz getopt_long() zamiast? Na większości platform, getopt() po prostu wywołuje _getopt_long() z przełącznikiem, aby wyłączyć długie argumenty. Tak jest w przypadku prawie każdej platformy, o której wiem (wciąż w użyciu), w tym Linux, BSD, a nawet wschodzących systemów operacyjnych takich jak HelenOS - wiem, że to ja poruszyłem getopt do jego biblioteki libc :)

O wiele łatwiej na KAŻDYM użyciu programu, aby mieć długie opcje, przynajmniej dopóki nie przyzwyczają się do korzystania z niego.

getopt_long() pozwoli ci na użycie dwóch (lub więcej) indeksów opcji, które mogą pozostać "na żywo" po zakończeniu przetwarzania argumentów, tylko wewnętrzny (globalny, nierecentrujący) musiałby zostać ponownie ustawiony to nie jest wielka sprawa.

Umożliwia to łatwe porównanie liczby argumentów z liczbą opcji faktycznie zrealizowanych w obu wywołaniach z wieloma innymi korzyściami.proszę nie używać przestarzałego interfejsu.

Spójrz na getopt.h, zobaczysz co mam na myśli.

+2

Definiowanie większości platform? HP-UX, Solaris, AIX - getopt() nie wywołuje getopt_long(). To 3 z 6 wariantów Uniksa (BSD, Linux, MacOS X to pozostałe, które mają znaczenie). –

2

Jak podano w manualu:

„program, który skanuje wielu wektorów argument lub skanuje ten sam wektor więcej niż raz, a chce skorzystać z rozszerzeń GNU takich jak«+»i«-» na początku operacji optstring lub zmienia wartość POSIXLY_CORRECT między skanami, należy ponownie zainicjować getopt(), resetując optind do 0, zamiast tradycyjnej wartości 1. (Resetowanie do 0 wymusza wywołanie procedury wewnętrznej inicjalizacji, która sprawdza ponownie POSIXLY_CORRECT i sprawdza rozszerzenia GNU w łańcuchu optstring.) "