Jak używać getopts do analizowania opcji skryptów powłoki systemu Linux?
Opublikowany: 2022-06-25 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.
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
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
Jeśli uruchomimy nasz skrypt bez parametrów, otrzymamy to wyjście.
./zmienne.sh
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
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ą
Jeśli umieścimy dwa słowa w cudzysłowie, są one traktowane jako jeden parametr.
./variables.sh jak "maniakiem"
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.
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
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
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
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
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
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
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.