Jak używać getopts do analizowania opcji skryptów powłoki systemu Linux?

Opublikowany: 2022-06-25
Ekran laptopa wyświetlający tekst terminala.
fatmawati achmad zaenuri/Shutterstock.com

Czy chciałbyś, aby twoje skrypty powłoki Linuksa lepiej obsługiwały opcje i argumenty wiersza poleceń? Wbudowane getopts Bash pozwala analizować opcje wiersza poleceń z finezją — i jest również łatwe. Pokażemy Ci jak.

Przedstawiamy wbudowane getopts

Przekazywanie wartości do skryptu Bash to dość prosta sprawa. Wywołujesz swój skrypt z wiersza poleceń lub z innego skryptu i podajesz listę wartości za nazwą skryptu. Te wartości są dostępne w skrypcie jako zmienne, zaczynając od $1 dla pierwszej zmiennej, $2 dla drugiej i tak dalej.

Ale jeśli chcesz przekazać opcje do skryptu, sytuacja szybko się komplikuje. Kiedy mówimy opcje, mamy na myśli opcje, flagi lub przełączniki, które mogą obsługiwać programy takie jak ls . Są one poprzedzone myślnikiem „ - ” i zwykle działają jako wskaźnik dla programu, aby włączyć lub wyłączyć jakiś aspekt jego funkcjonalności.

Jak używać polecenia ls do wyświetlania plików i katalogów w systemie Linux?
POWIĄZANE Jak używać polecenia ls do wyświetlania listy plików i katalogów w systemie Linux

Polecenie ls ma ponad 50 opcji, głównie związanych z formatowaniem wyjścia. Opcja -X (sortuj według rozszerzenia) sortuje dane wyjściowe alfabetycznie według rozszerzenia pliku. Opcja -U (niesortowana) wyświetla listę według kolejności katalogów.

Opcje są po prostu takie — są opcjonalne. Nie wiesz, których opcji — jeśli w ogóle — użytkownik zamierza użyć, ani nie wiesz, w jakiej kolejności może je wyświetlić w wierszu poleceń. Zwiększa to złożoność kodu wymaganego do przeanalizowania opcji.

Sprawy stają się jeszcze bardziej skomplikowane, jeśli niektóre z twoich opcji przyjmują argument znany jako argument opcji . Na przykład opcja ls -w (szerokość) oczekuje, że nastąpi po niej liczba reprezentująca maksymalną szerokość wyświetlania danych wyjściowych. I oczywiście możesz przekazać do swojego skryptu inne parametry, które są po prostu wartościami danych, które w ogóle nie są opcjami.

Na szczęście getopts poradzi sobie z tą złożonością. A ponieważ jest wbudowany, jest dostępny we wszystkich systemach z powłoką Bash, więc nie ma nic do zainstalowania.

Uwaga: getopts Nie getopt

Istnieje starsze narzędzie o nazwie getopt . Jest to mały program narzędziowy, a nie wbudowany. Istnieje wiele różnych wersji getopt z różnymi zachowaniami, podczas gdy wbudowane getops są zgodne z wytycznymi POSIX.

 wpisz getopts
 wpisz getopt 

używając polecenia type, aby zobaczyć różnicę między getop a getops

Ponieważ getopt nie jest wbudowany, nie dzieli niektórych automatycznych korzyści, jakie ma getopts , takich jak rozsądna obsługa białych znaków. Dzięki getopts powłoka Bash uruchamia twój skrypt, a powłoka Bash wykonuje parsowanie opcji. Nie musisz wywoływać zewnętrznego programu do obsługi parsowania.

Kompromis polega na tym, że getopts nie obsługuje podwójnie przekreślonych, długich nazw opcji. Możesz więc użyć opcji sformatowanych jak -w , ale nie „ ---wide-format ”. Z drugiej strony, jeśli masz skrypt, który akceptuje opcje -a , -b , i -c , getopts pozwala łączyć je jak -abc , -bca lub -bac i tak dalej.

W tym artykule omawiamy i demonstrujemy getopts , więc upewnij się, że dodałeś ostatnie „s” do nazwy polecenia.

POWIĄZANE: Jak uciec od spacji w ścieżkach plików w wierszu poleceń systemu Windows

Szybkie podsumowanie: obsługa wartości parametrów

Ten skrypt nie używa opcji przerywanych, takich jak -a lub -b . Akceptuje „normalne” parametry w wierszu poleceń i są one dostępne w skrypcie jako wartości.

 #!/kosz/bash

# pobieraj zmienne jedna po drugiej
echo "Zmienna 1: $1" 
echo "Zmienna druga: $2" 
echo "Zmienna trzecia: 3 USD"

# pętla przez zmienne
dla var w " $@" do
echo "$ zmienna" 
Gotowe

Parametry są dostępne w skrypcie jako zmienne $1 , $2 lub $3 .

Skopiuj ten tekst do edytora i zapisz go jako plik o nazwie „variables.sh”. Musimy uczynić go wykonywalnym poleceniem chmod . Musisz wykonać ten krok dla wszystkich omawianych przez nas skryptów. Wystarczy za każdym razem podstawić nazwę odpowiedniego pliku skryptu.

 chmod +x zmienne.sh 

za pomocą polecenia chmod, aby skrypt był wykonywalny

Jeśli uruchomimy nasz skrypt bez parametrów, otrzymamy to wyjście.

 ./zmienne.sh 

uruchamianie skryptu bez parametrów

Nie przekazaliśmy żadnych parametrów, więc skrypt nie ma wartości do zaraportowania. Tym razem podajmy kilka parametrów.

 ./variables.sh jak geek 

uruchomienie skryptu z trzema słowami jako parametrami

Zgodnie z oczekiwaniami zmienne $1 , $2 i $3 zostały ustawione na wartości parametrów i widzimy je wydrukowane.

Ten rodzaj obsługi parametrów jeden do jednego oznacza, że ​​musimy z góry wiedzieć, ile będzie parametrów. Pętla na dole skryptu nie dba o to, ile jest parametrów, zawsze przechodzi przez nie wszystkie.

Jeśli podajemy czwarty parametr, nie jest on przypisany do zmiennej, ale pętla nadal go obsługuje.

 ./variables.sh jak geekować stronę internetową 

przekazywanie czterech parametrów do skryptu, który obsługuje tylko trzy

Jeśli umieścimy dwa słowa w cudzysłowie, są one traktowane jako jeden parametr.

 ./variables.sh jak "maniakiem" 

cytowanie dwóch parametrów wiersza poleceń, aby były traktowane jako jeden parametr

Jeśli będziemy potrzebować naszego skryptu do obsługi wszystkich kombinacji opcji, opcji z argumentami i „normalnych” parametrów typu danych, będziemy musieli oddzielić opcje od zwykłych parametrów. Możemy to osiągnąć, umieszczając wszystkie opcje — z argumentami lub bez — przed zwykłymi parametrami.

Ale nie biegnijmy, zanim będziemy mogli chodzić. Spójrzmy na najprostszy przypadek obsługi opcji wiersza poleceń.

Opcje obsługi

Używamy getopts w pętli while . Każda iteracja pętli działa na jednej opcji, która została przekazana do skryptu. W każdym przypadku zmienna OPTION jest ustawiona na opcję identyfikowaną przez getopts .

Z każdą iteracją pętli getopts przechodzi do następnej opcji. Gdy nie ma więcej opcji, getopts zwraca wartość false , a pętla while kończy działanie.

Jak używać instrukcji przypadku w skryptach Bash
POWIĄZANE Jak używać instrukcji przypadku w skryptach Bash

Zmienna OPTION jest dopasowywana do wzorców w każdej z klauzul instrukcji case. Ponieważ używamy instrukcji case, nie ma znaczenia, w jakiej kolejności opcje są podawane w wierszu poleceń. Każda opcja jest wrzucana do instrukcji case i wyzwalana jest odpowiednia klauzula.

Poszczególne klauzule w instrukcji case ułatwiają wykonywanie akcji specyficznych dla opcji w skrypcie. Zazwyczaj w prawdziwym skrypcie ustawiasz zmienną w każdej klauzuli, a te działają jako flagi w dalszej części skryptu, zezwalając lub odmawiając niektórych funkcji.

Skopiuj ten tekst do edytora i zapisz go jako skrypt o nazwie „options.sh” i spraw, aby był wykonywalny.

 #!/kosz/bash

podczas gdy getopts 'abc' OPCJA; robić
  przypadek "$OPTION" w 
    a) 
      echo "Opcja używana" ;;

    b)
      echo "Użyto opcji b"
      ;;

    c)
      echo "Użyto opcji c"
      ;;

    ?) 
      echo "Użycie: $(nazwa podstawowa $0) [-a] [-b] [-c]"
      wyjście 1
      ;;
  esac
Gotowe

To jest linia, która definiuje pętlę while.

 podczas gdy getopts 'abc' OPCJA; robić

Po poleceniu getopts następuje ciąg opcji . To zawiera listę liter, których będziemy używać jako opcji. Jako opcje można używać tylko liter z tej listy. Więc w tym przypadku -d byłoby nieprawidłowe. Byłoby to uwięzione w klauzuli ?) , ponieważ getopts zwraca znak zapytania „ ? ” dla niezidentyfikowanej opcji. Jeśli tak się stanie, prawidłowe użycie jest wyświetlane w oknie terminala:

 echo "Użycie: $(nazwa podstawowa $0) [-a] [-b] [-c]"

Zgodnie z konwencją zawinięcie opcji w nawiasy kwadratowe „ [] ” w tym typie komunikatu o poprawnym użyciu oznacza, że ​​opcja jest opcjonalna. Polecenie basename usuwa wszystkie ścieżki katalogów z nazwy pliku. Nazwa pliku skryptu jest przechowywana w $0 w skryptach Bash.

Użyjmy tego skryptu z różnymi kombinacjami wiersza poleceń.

 ./opcje.sh -a
 ./opcje.sh -a -b -c
 ./opcje.sh -ab -c
 ./opcje.sh -kabina 

testowanie skryptu, który akceptuje opcje wiersza poleceń typu przełącznika

Jak widać, wszystkie nasze testowe kombinacje opcji są analizowane i obsługiwane poprawnie. Co jeśli wypróbujemy opcję, która nie istnieje?

 ./opcje.sh -d 

Nierozpoznana opcja zgłaszana przez powłokę i skrypt

Wywoływana jest klauzula use, co jest dobre, ale otrzymujemy również komunikat o błędzie z powłoki. To może, ale nie musi, mieć znaczenie dla twojego przypadku użycia. Jeśli wywołujesz skrypt z innego skryptu, który musi analizować komunikaty o błędach, utrudni to, jeśli powłoka również generuje komunikaty o błędach.

Wyłączenie komunikatów o błędach powłoki jest bardzo łatwe. Jedyne, co musimy zrobić, to wstawić dwukropek „ : ” jako pierwszy znak ciągu opcji.

Edytuj plik „options.sh” i dodaj dwukropek jako pierwszy znak ciągu opcji lub zapisz ten skrypt jako „options2.sh” i spraw, aby był wykonywalny.

 #!/kosz/bash

podczas gdy getops ':abc' OPCJA; robić
  przypadek "$OPTION" w 
    a) 
      echo "Opcja używana" 
      ;;

    b)
      echo "Użyto opcji b"
      ;;

    c)
      echo "Użyto opcji c"
      ;;

    ?) 
      echo "Użycie: $(nazwa podstawowa $0) [-a] [-b] [-c]"
      wyjście 1
      ;;
  esac
Gotowe

Kiedy uruchamiamy to i generujemy błąd, otrzymujemy własne komunikaty o błędach bez żadnych komunikatów powłoki.

 ./opcje2.sh.sh -d 

Nierozpoznana opcja zgłaszana przez sam skrypt

Używanie getopts z argumentami opcji

Aby poinformować getopts , że po opcji nastąpi argument, umieść dwukropek ” : ” bezpośrednio za literą opcji w łańcuchu opcji.

Jeśli po „b” i „c” w naszym łańcuchu opcji zastosujemy dwukropki, getopt będzie oczekiwał argumentów dla tych opcji. Skopiuj ten skrypt do swojego edytora i zapisz go jako „arguments.sh” i spraw, aby był wykonywalny.

Pamiętaj, że pierwszy dwukropek w łańcuchu opcji jest używany do pomijania komunikatów o błędach powłoki — nie ma to nic wspólnego z przetwarzaniem argumentów.

Kiedy getopt przetwarza opcję z argumentem, argument jest umieszczany w zmiennej OPTARG . Jeśli chcesz użyć tej wartości w innym miejscu w skrypcie, musisz skopiować ją do innej zmiennej.

 #!/kosz/bash

while getopts ':ab:c:' OPCJA; robić

  przypadek "$OPTION" w
    a)
      echo "Opcja używana"
      ;;

    b)
      argB="$OPTARG"
      echo "Opcja b używana z: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Opcja c używana z: $argC"
      ;;

    ?)
      echo "Sposób użycia: $(nazwa podstawowa $0) [-a] [-b argument] [-c argument]"
      wyjście 1
      ;;
  esac

Gotowe

Przeprowadźmy to i zobaczmy, jak to działa.

 ./arguments.sh -a -b "jak geek" -c reviewgeek
 ./arguments.sh -c reviewgeek -a 

testowanie skryptu obsługującego argumenty opcji

Więc teraz możemy obsługiwać opcje z argumentami lub bez, niezależnie od kolejności ich podania w wierszu poleceń.

Ale co ze zwykłymi parametrami? Powiedzieliśmy wcześniej, że wiedzieliśmy, że będziemy musieli umieścić je w wierszu poleceń po jakichkolwiek opcjach. Zobaczmy, co się stanie, jeśli to zrobimy.

Opcje i parametry mieszania

Zmienimy nasz poprzedni skrypt, aby zawierał jeszcze jedną linię. Po zakończeniu pętli while i wykonaniu wszystkich opcji spróbujemy uzyskać dostęp do zwykłych parametrów. Wydrukujemy wartość w $1 .

Zapisz ten skrypt jako „arguments2.sh” i uczyń go wykonywalnym.

 #!/kosz/bash

while getopts ':ab:c:' OPCJA; robić

  przypadek "$OPTION" w
    a)
      echo "Opcja używana"
      ;;

    b)
      argB="$OPTARG"
      echo "Opcja b używana z: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Opcja c używana z: $argC"
      ;;

    ?)
      echo "Sposób użycia: $(nazwa podstawowa $0) [-a] [-b argument] [-c argument]"
      wyjście 1
      ;;
  esac

Gotowe

echo "Zmienna to: $1"

Teraz wypróbujemy kilka kombinacji opcji i parametrów.

 ./arguments2.sh dave
 ./arguments2.sh -a dave
 ./arguments2.sh -a -c jak geek dave 

Brak dostępu do standardowych parametrów w skrypcie, który akceptuje argumenty opcji

Więc teraz widzimy problem. Jak tylko zostaną użyte jakiekolwiek opcje, zmienne od $1 są wypełniane flagami opcji i ich argumentami. W ostatnim przykładzie $4 zawierałoby wartość parametru „dave”, ale jak uzyskać do niej dostęp w skrypcie, jeśli nie wiesz, ile opcji i argumentów zostanie użytych?

Odpowiedzią jest użycie OPTIND i polecenia shift .

Polecenie shift usuwa pierwszy parametr — niezależnie od typu — z listy parametrów. Pozostałe parametry „tasują”, więc parametr 2 staje się parametrem 1, parametr 3 staje się parametrem 2 i tak dalej. I tak $2 staje się $1 , $3 staje się $2 , i tak dalej.

Jeśli podasz shift z liczbą, usunie to wiele parametrów z listy.

OPTIND zlicza opcje i argumenty w miarę ich znajdowania i przetwarzania. Po przetworzeniu wszystkich opcji i argumentów OPTIND będzie o jeden większy niż liczba opcji. Jeśli więc użyjemy parametrów shift to trim (OPTIND-1) z listy parametrów, pozostaną zwykłe parametry od $1 .

Dokładnie to robi ten skrypt. Zapisz ten skrypt jako „arguments3.sh” i uczyń go wykonywalnym.

 #!/kosz/bash

while getopts ':ab:c:' OPCJA; robić
  przypadek "$OPTION" w
    a)
      echo "Opcja używana"
      ;;

    b)
      argB="$OPTARG"
      echo "Opcja b używana z: $argB"
      ;;

    c)
      argC="$OPTARG"
      echo "Opcja c używana z: $argC"
      ;;

    ?)
      echo "Sposób użycia: $(nazwa podstawowa $0) [-a] [-b argument] [-c argument]"
      wyjście 1
      ;;
  esac
Gotowe

echo "Przed - zmienna pierwsza to: $1"
przesunięcie "$(($OPTIND -1))"
echo "Po - zmienna pierwsza to: $1"
echo "Pozostałe argumenty (operandy)"

dla x w "$@"
robić
  echo $x
Gotowe

Uruchomimy to z mieszanką opcji, argumentów i parametrów.

 ./arguments3.sh -a -c jak-to-geek "dave dee" dozy beaky mick tich 

Poprawny dostęp do standardowych parametrów w skrypcie akceptującym argumenty opcji

Widzimy, że zanim wywołaliśmy shift , $1 zawierał „-a”, ale po poleceniu shift $1 zawiera nasz pierwszy nie będący opcją, parametr nieargumentowy. Możemy przejść przez wszystkie parametry w pętli tak łatwo, jak w skrypcie bez parsowania opcji.

Zawsze dobrze jest mieć opcje

Obsługa opcji i ich argumentów w skryptach nie musi być skomplikowana. Za pomocą getopts można tworzyć skrypty, które obsługują opcje wiersza poleceń, argumenty i parametry dokładnie tak, jak powinny być zgodne z natywnymi skryptami zgodnymi z POSIX.