getopt

Getopt to funkcja biblioteki C używana do analizowania opcji wiersza poleceń w stylu Unix/POSIX. Jest częścią POSIX i jest uniwersalna dla systemów uniksopodobnych . Jest to również nazwa programu uniksowego do analizowania argumentów wiersza poleceń w skryptach powłoki.

Historia

Od dawna problemem związanym z programami wiersza poleceń był sposób określania opcji; wczesne programy wykorzystywały wiele sposobów, w tym opcje jednoznakowe ( -a ), wiele opcji określonych razem ( -abc jest równoważne z -a -b -c ), opcje wieloznakowe ( -inum ), opcje z argumentami ( -a arg , -inum 3 , -a=arg ) i różne znaki prefiksu ( -a , +b , /c ).

Funkcja getopt została napisana jako standardowy mechanizm, którego wszystkie programy mogłyby używać do analizowania opcji wiersza poleceń, tak aby istniał wspólny interfejs, na którym wszyscy mogliby polegać. W związku z tym oryginalni autorzy wybrali spośród odmian obsługę opcji jednoznakowych, wielu opcji określonych razem oraz opcji z argumentami ( -a arg lub -aarg ), wszystkie kontrolowane przez ciąg opcji.

getopt pochodzi z co najmniej 1980 roku i został po raz pierwszy opublikowany przez AT&T na konferencji UNIFORUM w 1985 roku w Dallas w Teksasie z zamiarem udostępnienia go jako domeny publicznej. [ potrzebne źródło ] Jego wersje zostały później przechwycone przez inne odmiany Uniksa ( 4.3BSD , Linux , itp.). Jest określony w POSIX.2 jako część pliku nagłówkowego unistd.h . Pochodne getopt zostały stworzone dla wielu języków programowania w celu analizowania opcji wiersza poleceń.

Rozszerzenia

getopt jest funkcją zależną od systemu, a jej zachowanie zależy od implementacji w bibliotece C. Dostępne są jednak niektóre niestandardowe implementacje, takie jak gnulib .

Konwencjonalna obsługa (POSIX i BSD) polega na tym, że opcje kończą się, gdy napotkany zostanie pierwszy argument nie będący opcją, a getopt zwróci -1, aby to zasygnalizować. Jednak w glibc opcje są dozwolone w dowolnym miejscu dla ułatwienia użycia; getopt niejawnie permutuje wektor argumentów, więc na końcu nadal pozostawia brak opcji. Ponieważ POSIX ma już konwencję zwracania -1 na -- i pomijania go, zawsze można go używać jako przenośnego znacznika końca opcji.

Rozszerzenie GNU , getopt_long , umożliwia analizowanie bardziej czytelnych, wieloznakowych opcji, które są wprowadzane przez dwie kreski zamiast jednej. Wybór dwóch kresek umożliwia odróżnienie opcji wieloznakowych ( --inum ) od opcji jednoznakowych określonych razem ( -abc ). Rozszerzenie GNU pozwala również na alternatywny format opcji z argumentami: --name=arg . Ten interfejs okazał się popularny i został przyjęty (bez permutacji) przez wiele dystrybucji BSD, w tym FreeBSD , a także Solaris . Alternatywny sposób obsługi długich opcji jest widoczny w Solarisie i Korn Shell (rozszerzanie optstring ), ale nie był tak popularny.

Innym powszechnym zaawansowanym rozszerzeniem getopt jest resetowanie stanu analizowania argumentów; jest to przydatne jako zamiennik rozszerzenia GNU options-anyware lub jako sposób na „warstwę” zestawu interfejsu wiersza poleceń z różnymi opcjami na różnych poziomach. Osiąga się to w systemach BSD za pomocą optreset , aw systemach GNU przez ustawienie optind na 0.

Wspólną funkcją towarzyszącą getopt jest getsubopt . Analizuje ciąg opcji podrzędnych oddzielonych przecinkami.

Stosowanie

Dla użytkowników

Składnia wiersza poleceń dla programów opartych na getopt to zalecana przez POSIX składnia Utility Argument. W skrócie:

  • Opcje to pojedyncze znaki alfanumeryczne poprzedzone znakiem - (myślnik-minus).
  • Opcje mogą przyjąć argument, obowiązkowy lub opcjonalny, lub żaden.
  • Aby określić, że opcja przyjmuje argument, należy dołączyć : po nazwie opcji (tylko przy wstępnej specyfikacji)
  • Gdy opcja przyjmuje argument, może to być ten sam token lub następny. Innymi słowy, jeśli o przyjmuje argument, -ofoo jest tym samym co -o foo .
  • Wiele opcji można łączyć ze sobą, o ile te, które nie są ostatnimi, nie są argumentami. Jeśli aib nie przyjmują żadnych argumentów, podczas gdy e przyjmuje opcjonalny argument, -abe jest tym samym co -a -b -e , ale -bea nie jest tym samym co -b -ea ze względu na poprzednią regułę.
  • Wszystkie opcje poprzedzają argumenty nie będące opcjami (z wyjątkiem w rozszerzeniu GNU). -- zawsze oznacza koniec opcji.

Rozszerzenia dotyczące składni obejmują konwencję GNU i specyfikację CLIP firmy Sun.

Dla programistów

Podręcznik getopt z GNU określa takie użycie dla getopt:

 

      
              #include  <unistd.h>  int  getopt  (  int  argc  ,  char  *  const  argv  [],  const  char  *  optstring  ); 

Tutaj argc i argv są zdefiniowane dokładnie tak, jak w prototypie głównej funkcji C; tj. argc wskazuje długość tablicy łańcuchów argv. Ciąg optstring zawiera specyfikację, jakich opcji szukać (zwykłe znaki alfanumeryczne z wyjątkiem W ) i jakie opcje akceptować argumenty (dwukropki). Na przykład „vf::o:” odnosi się do trzech opcji: bezargumentowej v , opcjonalnego argumentu f i obowiązkowego argumentu o . GNU implementuje tutaj W dla długich synonimów opcji.

getopt zwraca liczbę całkowitą, która jest albo znakiem opcji, albo -1 dla końca opcji. Idiom polega na użyciu pętli while do przeglądania opcji i użyciu instrukcji switch-case do wybierania opcji i działania na nich. Zobacz przykładową sekcję tego artykułu.

Aby przekazać dodatkowe informacje z powrotem do programu, program odwołuje się do kilku globalnych zmiennych zewnętrznych w celu pobrania informacji z getopt :

  
     extern  char  *  optarg  ;  extern  int  optind  ,  opterr  ,  optopt  ; 
optarg
Wskaźnik do argumentu bieżącej opcji, jeśli jest obecny. Może być używany do kontrolowania, gdzie rozpocząć parsowanie (ponownie).
optind
Gdzie getopt aktualnie patrzy w argv .
opterr
Przełącznik logiczny określający, czy getopt powinien drukować komunikaty o błędach.
otopt
Jeśli wystąpi nierozpoznana opcja, wartość tego nierozpoznanego znaku.

Interfejs GNU getopt_long jest podobny, chociaż należy do innego pliku nagłówkowego i ma dodatkową opcję definiowania „krótkich” nazw długich opcji oraz kilka dodatkowych elementów sterujących. Jeśli krótka nazwa nie jest zdefiniowana, getopt zamiast tego umieści indeks odnoszący się do struktury opcji we longindex .

 

      
                  
                      #include  <getopt.h>  int  getopt_long  (  int  argc  ,  char  *  const  argv  [],  const  char  *  optstring  ,  const  struct  opcja  *  longopts  ,  int  *  longindex  ); 

Przykłady

Korzystanie ze standardowego getopt POSIX

 
 
 
      
     
       0
       0   0
       0   0
            
               
          
         
         
         
               0     
                 
            
              
              
            
         
             
              
            
         
             
              
            
         
              
              
            
         
              
              
            
         
            
        
              
        
    
        
         
            
              
        
         
    
     0
 #include  <stdio.h>  /* dla printf */  #include  <stdlib.h>  /* dla wyjścia */  #include  <unistd.h>  /* dla getopt */  int  main  (  int  argc  ,  char  **  argv  )  {  int  c  ;  int  cyfra_opcja  =  ;  int  aopt  =  ,  bopt  =  ;  char  *  kopt  =  ,  *  dopt  =  ;  while  ((  c  =  getopt  (  argc  ,  argv  ,  "abc:d:012"  ))  !=  -1  )  {  int  this_option_optind  =  optind  ?  opcja wyboru  :  1  ;  switch  (  c  )  {  case  '0'  :  case  '1'  :  case  '2'  :  if  (  digit_optind  !=  &&  digit_optind  !=  this_option_optind  )  {  printf  (  "cyfry występują w dwóch różnych elementach argv.  \n  "  );  }  optymalizacja_cyfry  =  optymalizacja_ta_opcja  ;  printf  (  "opcja %c  \n  "  ,  c  );  przerwa  ;  case  'a'  :  printf  (  "opcja a  \n  "  );  aopt  =  1  ;  przerwa  ;  case  'b'  :  printf  (  "opcja b  \n  "  );  bopt  =  1  ;  przerwa  ;  case  'c'  :  printf  (  "opcja c o wartości '%s'  \n  "  ,  optarg  );  kopt  =  optarg  ;  przerwa  ;  case  'd'  :  printf  (  "opcja d o wartości '%s'  \n  "  ,  optarg  );  dopt  =  optarg  ;  przerwa  ;  sprawa  '?'  :  przerwa  ;  domyślnie  :  printf  (  "?? getopt zwrócił kod znaku 0%o ??  \n  "  ,  c  );  }  }  if  (  optind  <  argc  )  {  printf  (  "nieopcjonalne elementy ARGV: "  );  while  (  optind  <  argc  )  {  printf  (  "%s "  ,  argv  [  optind  ++  ]);  }  printf  (  "  \n  "  );  }  wyjdź  (  );  } 

Korzystanie z rozszerzenia GNU getopt_long

 
 
 
      
     
       0
       0   0
       0   0
         
    
               0
                  0
            0
                 0
            
              0
              0                  0
    
       0
         
                     
               
          
         0
              
              
                  
            
             
            
         
         
         
               0     
                 
            
              
              
            
         
             
              
            
         
             
              
            
         
              
              
            
         
              
              
            
         
            
        
              
        
    
        
         
            
              
        
         
    
     0
 #include  <stdio.h>  /* dla printf */  #include  <stdlib.h>  /* dla wyjścia */  #include  <getopt.h>  /* dla getopt_long; Getopt w standardzie POSIX znajduje się w unistd.h */   int  main  (  int  argc  ,  char  **  argv  )  {  int  c  ;  int  cyfra_opcja  =  ;  int  aopt  =  ,  bopt  =  ;  char  *  kopt  =  ,  *  dopt  =  ;  static  struct  opcja  long_options  []  =  {  /* NAZWA KRÓTKA NAZWA FLAGI ARGUMENTU */  {  "dodaj"  ,  wymagany_argument  ,  NULL  ,  },  {  "dołącz"  ,  brak_argumentów  ,  NULL  ,  },  {  "usuń"  ,  wymagany_argument  ,  NULL  ,  },  {  "verbose"  ,  no_argument  ,  NULL  ,  },  {  "create"  ,  wymagane_argument  ,  NULL  ,  'c'  },  {  "plik"  ,  wymagany_argument  ,  NULL  ,  },  {  NULL  ,  ,  NULL  ,  }  };  int  indeks_opcji  =  ;  while  ((  c  =  getopt_long  (  argc  ,  argv  ,  "abc:d:012"  ,  long_options  &  option_index  ))  !  =  -1  )  {  int  this_option_optind  =  optind  ?  opcja wyboru  :  1  ;  switch  (  c  )  {  case  :  printf  (  "opcja %s"  ,  long_options  [  indeks_opcji  ].  nazwa  );  if  (  optarg  )  {  printf  (  " with arg %s"  ,  optarg  );  }  printf  (  "  \n  "  );  przerwa  ;  przypadek  '0'  :  przypadek  '1'  :  przypadek  '2'  :  if  (  opt_cyfry  !=  &&  optym_cyfr  !=  opcja_opcji_ta  )  {  printf  (  "cyfry występują w dwóch różnych elementach argv.  \n  "  );  }  cyfra_opcja  =  ta_opcja_opcja  ;  printf  (  "opcja %c  \n  "  ,  c  );  przerwa  ;  case  'a'  :  printf  (  "opcja a  \n  "  );  aopt  =  1  ;  przerwa  ;  case  'b'  :  printf  (  "opcja b  \n  "  );  bopt  =  1  ;  przerwa  ;  case  'c'  :  printf  (  "opcja c o wartości '%s'  \n  "  ,  optarg  );  kopt  =  optarg  ;  przerwa  ;  case  'd'  :  printf  (  "opcja d o wartości '%s'  \n  "  ,  optarg  );  dopt  =  optarg  ;  przerwa  ;  sprawa  '?'  :  przerwa  ;  domyślnie  :  printf  (  "?? getopt zwrócił kod znaku 0%o ??  \n  "  ,  c  );  }  }  if  (  optind  <  argc  )  {  printf  (  "nieopcjonalne elementy ARGV: "  );  while  (  optind  <  argc  )  {  printf  (  "%s "  ,  argv  [  optind  ++  ]);  }  printf  (  "  \n  "  );  }  wyjdź  (  );  } 

W skorupkach

Programiści skryptów powłoki zwykle chcą zapewnić spójny sposób dostarczania opcji. Aby osiągnąć ten cel, zwracają się do getopts i starają się przenieść go na swój własny język.

Pierwszą próbą przeniesienia był program getopt , wdrożony przez Unix System Laboratories (USL). Ta wersja nie była w stanie poradzić sobie z cytowaniem i metaznakami powłoki, ponieważ nie wykazuje żadnych prób cytowania. Został odziedziczony po FreeBSD.

W 1986 roku firma USL zdecydowała, że ​​niebezpieczeństwo związane z metaznakami i białymi znakami nie jest już akceptowane i zamiast tego stworzyło wbudowane polecenie getopts dla Unix SVR3 Bourne Shell. Zaletą wbudowania polecenia w powłokę jest to, że ma ono teraz dostęp do zmiennych powłoki, więc wartości mogą być bezpiecznie zapisywane bez cytowania. Używa własnych zmiennych powłoki do śledzenia pozycji bieżących i pozycji argumentów, OPTIND i OPTARG , i zwraca nazwę opcji w zmiennej powłoki.

W 1995 getopts został włączony do Single UNIX Specification version 1 / X/Open Portability Guidelines, wydanie 4. Teraz, jako część standardu powłoki POSIX, getopts rozprzestrzenił się daleko w wielu innych powłokach próbujących być zgodnych z POSIX.

getopt został w zasadzie zapomniany, dopóki util-linux nie wyszedł z ulepszoną wersją, która naprawiła wszystkie stare problemy getopt przez ucieczkę. Obsługuje również długie nazwy opcji GNU. Z drugiej strony, długie opcje były rzadko implementowane w getopts w innych powłokach, z wyjątkiem ksh93 .

W innych językach

getopt to zwięzły opis wspólnej struktury argumentów poleceń POSIX i jest szeroko powielany przez programistów starających się zapewnić podobny interfejs, zarówno dla siebie, jak i dla użytkownika w wierszu poleceń.

  • C: systemy inne niż POSIX nie dostarczają getopt w bibliotece C, ale gnulib i MinGW (oba akceptują styl GNU), jak również niektóre bardziej minimalne biblioteki, mogą być użyte do zapewnienia tej funkcjonalności. Istnieją również alternatywne interfejsy:
    • Biblioteka popt , używana przez menedżera pakietów RPM , ma tę dodatkową zaletę, że jest reentrant .
    • Rodzina funkcji argp w bibliotekach glibc i gnulib zapewnia większą wygodę i modułowość.
  • Język programowania D : ma moduł getopt w standardowej bibliotece D.
  • Go : jest dostarczany z pakietem flag , który pozwala na długie nazwy flag. Pakiet getopt obsługuje przetwarzanie bliższe funkcji C. Istnieje również inny getopt zapewniający interfejs znacznie bliższy oryginalnemu pakietowi POSIX.
  • Haskell : zawiera System.Console.GetOpt, który jest zasadniczo portem Haskella biblioteki GNU getopt.
  • Java : W standardowej bibliotece Java nie ma implementacji getopt. Istnieje kilka modułów open source, w tym gnu.getopt.Getopt, który jest przeniesiony z GNU getopt, oraz Apache Commons CLI.
  • Lisp : ma wiele różnych dialektów bez wspólnej biblioteki standardowej. Istnieje kilka zewnętrznych implementacji getopt dla niektórych dialektów Lispa. Common Lisp ma wybitną implementację strony trzeciej.
  • Free Pascal : ma własną implementację jako jedną ze swoich standardowych jednostek o nazwie GetOpts. Jest obsługiwany na wszystkich platformach.
  • Język programowania Perl : ma dwie oddzielne pochodne getopt w swojej standardowej bibliotece: Getopt::Long i Getopt::Std.
  • PHP : ma funkcję getopt.
  • Python : zawiera moduł w swojej standardowej bibliotece oparty na rozszerzeniach getopt i GNU języka C. Standardowa biblioteka Pythona zawiera również inne moduły do ​​analizowania opcji, które są wygodniejsze w użyciu.
  • Ruby : ma implementację getopt_long w swojej standardowej bibliotece GetoptLong. Ruby ma również moduły w swojej standardowej bibliotece z bardziej wyrafinowanym i wygodnym interfejsem. Dostępna jest implementacja oryginalnego interfejsu getopt innej firmy.
  • .NET Framework : nie ma funkcji getopt w swojej standardowej bibliotece. Dostępne są implementacje innych firm.

Linki zewnętrzne