Chciałbym mieć długie i krótkie formy opcji wiersza poleceń wywoływanych za pomocą mojego skryptu powłoki.
Wiem, że getopts
można tego użyć, ale podobnie jak w Perlu, nie byłem w stanie zrobić tego samego z powłoką.
Wszelkie pomysły, jak to zrobić, aby móc korzystać z opcji takich jak:
./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/
W powyższym, oba polecenia oznaczają to samo dla mojej powłoki, ale używając getopts
, nie byłem w stanie ich wdrożyć?
bash
command-line-arguments
getopt
getopts
gagneet
źródło
źródło
Odpowiedzi:
Można rozważyć trzy implementacje:
Wbudowane Bash
getopts
. Nie obsługuje to długich nazw opcji z prefiksem podwójnego myślnika. Obsługuje tylko opcje jednoznakowe.Implementacja BSD UNIX samodzielnego
getopt
polecenia (tego używa MacOS). To również nie obsługuje długich opcji.Implementacja GNU autonomicznego
getopt
. GNUgetopt(3)
(używany w wierszu poleceńgetopt(1)
w systemie Linux) obsługuje długie opcje parsowania.Niektóre inne odpowiedzi pokazują rozwiązanie używania wbudowanego basha
getopts
do naśladowania długich opcji. To rozwiązanie faktycznie stanowi krótką opcję, której znak to „-”. Otrzymujesz „-” jako flagę. Następnie wszystko, co następuje, staje się OPTARG, a testujesz OPTARG z zagnieżdżonymcase
.Jest to sprytne, ale wiąże się z pewnymi zastrzeżeniami:
getopts
nie może egzekwować specyfikacji opt. Nie może zwrócić błędów, jeśli użytkownik poda nieprawidłową opcję. Podczas analizy OPTARG musisz wykonać własne sprawdzanie błędów.Tak więc, chociaż można napisać więcej kodu, aby obejść brak obsługi długich opcji, jest to o wiele więcej pracy i częściowo odrzuca cel użycia parsera getopt w celu uproszczenia kodu.
źródło
getopt
igetopts
są różnymi zwierzętami, a ludzie wydają się mieć trochę niezrozumienia tego, co robią.getopts
to wbudowane polecenie dobash
przetwarzania opcji wiersza polecenia w pętli i przypisywania każdej znalezionej opcji i wartości kolejno do wbudowanych zmiennych, aby można było je dalej przetwarzać.getopt
jest jednak zewnętrznym programem narzędziowym i tak naprawdę nie przetwarza twoich opcji tak, jak robią to np. bashgetopts
,Getopt
moduł Perl lub moduły Pythonoptparse
/argparse
. Wystarczygetopt
kanonizować przekazane opcje - tzn. Przekonwertować je na bardziej standardową formę, aby skrypt powłoki mógł je łatwiej przetwarzać. Na przykład aplikacjagetopt
może konwertować następujące elementy:zaangażowany w to:
Rzeczywiste przetwarzanie należy wykonać samodzielnie. Nie musisz wcale używać,
getopt
jeśli wprowadzasz różne ograniczenia w sposobie określania opcji:-o
powyżej) wartość musi być oddzielnym argumentem (po spacji).Dlaczego warto korzystać
getopt
zamiastgetopts
? Podstawowym powodem jest to, że tylko GNUgetopt
zapewnia obsługę opcji wiersza polecenia o długiej nazwie. 1 (GNUgetopt
jest domyślny w Linuksie. Mac OS X i FreeBSD są dostarczane z podstawowym i niezbyt przydatnym programemgetopt
, ale wersję GNU można zainstalować; patrz poniżej.)Na przykład, oto przykład użycia GNU
getopt
, z mojego skryptu o nazwiejavawrap
:Pozwala to określić opcje takie jak
--verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
lub podobne. Efektem wywołaniagetopt
jest kanonizacja opcji, aby--verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
można było łatwiej je przetworzyć. Cytowanie wokół"$1"
i"$2"
jest ważne, ponieważ zapewnia, że argumenty ze spacjami są poprawnie obsługiwane.Jeśli usuniesz pierwsze 9 wierszy (wszystko wzdłuż
eval set
linii), kod nadal będzie działał ! Jednak twój kod będzie znacznie bardziej wybitny pod względem rodzajów akceptowanych opcji: W szczególności będziesz musiał określić wszystkie opcje w opisanej powyżej „kanonicznej” formie. Za pomocągetopt
jednak można grupować opcje jednoliterowe, stosować krótsze, niejednoznaczne formy długich opcji, używać albo--file foo.txt
lub--file=foo.txt
, używać albo-m 4096
lub-m4096
, mieszać opcje i nie-opcje w dowolnej kolejności itp.getopt
wyświetla również komunikat o błędzie, jeśli znaleziono nierozpoznane lub niejednoznaczne opcje.UWAGA : W rzeczywistości istnieją dwie całkowicie różne wersje
getopt
, Basicgetopt
i GNUgetopt
, z różnymi funkcjami i różnymi konwencjami wywoływania. 2 Podstawowygetopt
jest dość zepsuty: nie tylko nie obsługuje długich opcji, nie może nawet obsługiwać spacji wewnątrz argumentów lub pustych argumentów, podczas gdygetopts
robi to dobrze. Powyższy kod nie będzie działał w podstawowym językugetopt
. GNUgetopt
jest instalowane domyślnie w systemie Linux, ale w Mac OS X i FreeBSD należy je instalować osobno. W systemie Mac OS X zainstaluj MacPorts ( http://www.macports.org ), a następnie zrób to,sudo port install getopt
aby zainstalować GNUgetopt
(zwykle w/opt/local/bin
) i upewnij się, że/opt/local/bin
znajduje się on na ścieżce powłoki przed/usr/bin
. Na FreeBSD zainstalujmisc/getopt
.Krótki przewodnik po modyfikowaniu przykładowego kodu dla własnego programu: z pierwszych kilku linii wszystko jest „płytką kotłową”, która powinna pozostać niezmieniona, z wyjątkiem linii, która wywołuje
getopt
. Powinieneś zmienić nazwę programu po-n
, określić krótkie opcje po-o
i długie opcje po--long
. Umieść dwukropek po opcjach, które przyjmują wartość.Wreszcie, jeśli widzisz kod, który właśnie
set
zamiast tegoeval set
, został napisany dla BSDgetopt
. Powinieneś to zmienić, aby użyćeval set
stylu, który działa dobrze w obu wersjachgetopt
, podczas gdy zwykłyset
nie działa poprawnie z GNUgetopt
.1 Faktycznie,
getopts
wksh93
podporach długo nazwie opcje, ale ta skorupa nie jest używany tak często, jakbash
. Wzsh
użyj,zparseopts
aby uzyskać tę funkcjonalność.2 Technicznie „GNU
getopt
” jest mylącą nazwą; ta wersja została napisana dla Linuksa, a nie dla projektu GNU. Jest jednak zgodny ze wszystkimi konwencjami GNU, a termin „GNUgetopt
” jest powszechnie używany (np. W FreeBSD).źródło
getopt
w Linuksie nie jest narzędziem GNU, a tradycyjnegetopt
nie pochodzi z BSD, ale z AT&T Unix. ksh93'sgetopts
(również z AT&T) obsługuje długie opcje w stylu GNU.POSIXLY_CORRECT
), podczas gdy „getopt z rozszerzeniem Linux” błędnie sugeruje, że ta wersja istnieje tylko na Linuxgetopt
można łatwo przenieść na inne Uniksy, ale wiele innych programówutil-linux
jest specyficznych dla Linuksa). Wszystkie programy inne niż GNU korzystające z GNU getopt (3) rozumieją$POSIX_CORRECT
. Na przykład nie powiedziałbyś, żeaplay
to GNU tylko z tych powodów. Podejrzewam, że kiedy FreeBSD wspomina o GNU getopt, oznacza to interfejs API GNU getopt (3) C.getopt
util, a nie getopt (3).Wbudowana funkcja getopts Bash może być używana do analizowania długich opcji poprzez wstawienie znaku myślnika, a następnie dwukropka w optspec:
Po skopiowaniu do pliku wykonywalnego name =
getopts_test.sh
w bieżącym katalogu roboczym można wygenerować dane wyjściowe podobne doOczywiście getopts nie
OPTERR
sprawdza ani nie analizuje argumentów opcji dla długich opcji. Powyższy fragment skryptu pokazuje, jak można to zrobić ręcznie. Podstawowa zasada działa również w skorupie Debiana Almquist („dash”). Zwróć uwagę na szczególny przypadek:Zauważ, że jak zauważył GreyCat z http://mywiki.wooledge.org/BashFAQ , ta sztuczka wykorzystuje niestandardowe zachowanie powłoki, które pozwala na argument-opcja (tj. Nazwa pliku w „-f nazwa pliku”) do powiązania z opcją (jak w „-nazwa_pliku”). Standard POSIX mówi, że musi być między nimi spacja, która w przypadku „- longoption” przerwałaby parsowanie opcji i zamieniła wszystkie longoptions w argumenty niebędące opcjami.
źródło
!
wval="${!OPTIND}
?getopts
automatycznie zwiększamy tylkoOPTIND
o 1, ale w naszym przypadku musimy zwiększyć o 2, więc zwiększamy o 1 ręcznie, a następnie automatyczniegetopts
zwiększamy o 1.$
konieczne.OPTIND=$(( $OPTIND + 1 ))
może być sprawiedliwyOPTIND=$(( OPTIND + 1 ))
. Co ciekawsze, możesz nawet przypisywać i zwiększać zmienne w wyrażeniu arytmetycznym, dzięki czemu można dalej go skracać: $(( ++OPTIND ))
, a nawet(( ++OPTIND ))
brać pod uwagę, że++OPTIND
zawsze będzie dodatni, aby nie wywoływał uruchomienia powłoki z tą-e
opcją. :-) gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html--very-bad
daje ostrzeżenia?Wbudowany
getopts
polecenie jest nadal, AFAIK, ograniczone tylko do opcji jednoznakowych.Istnieje (lub był) program zewnętrzny
getopt
, który reorganizowałby zestaw opcji, dzięki czemu łatwiej go było przeanalizować. Możesz dostosować ten projekt do obsługi długich opcji. Przykładowe użycie:Możesz użyć podobnego schematu z
getoptlong
poleceniem.Zauważ, że podstawową słabością
getopt
programu zewnętrznego jest trudność w obsłudze argumentów ze spacjami w nich oraz w ich dokładnym zachowaniu. Dlatego wbudowanygetopts
jest lepszy, aczkolwiek ograniczony faktem, że obsługuje tylko opcje jednoliterowe.źródło
eval set
cytaty (zobacz moją odpowiedź poniżej), aby działał poprawnie z GNU getopt (domyślnie w Linuksie) i poprawnie obsługiwał spacje.${1+"$@"}
. Jest osobliwy i kłóci się z tym, co jest konieczne w nowoczesnych pocisków a konkretnie z każdej muszli chcesz wybrać się na Linux Patrz Korzystanie $ 1: + „$ @”} w / bin / sh Przez omówienie tego zapisu.)eval set
robi to dobrze zarówno z GNU, jak i BSDgetopt
, podczas gdy zwykłyset
robi to samo z BSDgetopt
. Równie dobrze możesz wykorzystać,eval set
aby zachęcić ludzi do przyzwyczajenia się do robienia tego. BTW dzięki, nie zdawałem sobie sprawy, że${1+"$@"}
to już nie jest potrzebne. Muszę pisać rzeczy, które działają zarówno w systemie Mac OS X, jak i Linux - między nimi wymuszają dużą przenośność. Właśnie sprawdziłem i"$@"
rzeczywiście postąpić właściwie na wszystkosh
,bash
,ksh
, izsh
pod Mac OS X; na pewno także pod Linuksem.Oto przykład, który faktycznie używa getopt z długimi opcjami:
źródło
eval set
z cudzysłowami (patrz moja odpowiedź poniżej), aby działał poprawnie z GNU getopt (domyślnie w Linuksie) i poprawnie obsługiwał spacje.getopt
gdy chodzi o pytaniegetopts
.(--
,(-*
i(*
ważne wzory? Jak są one różne od--
,-*
i*
?(--)
jest identyczny jak--)
wcase
zwrotce. Dziwnie jest widzieć nierównomierne wcięcie i niespójne użycie tych opcjonalnych wiodących parenów, ale aktualny kod odpowiedzi wydaje mi się ważny.Długie opcje mogą być analizowane przez standardowe narzędzie
getopts
jako „argumenty” do-
„opcji”Jest to przenośna i rodzima powłoka POSIX - nie są potrzebne żadne zewnętrzne programy ani bashizmy.
Ten przewodnik implementuje długie opcje jako argumenty dla
-
opcji, dlatego--alpha
jest postrzeganygetopts
jako-
z argumentemalpha
i--bravo=foo
jako-
z argumentembravo=foo
. Prawdziwy argumentem mogą być zbierane z prostego zastąpienia:${OPTARG#*=}
.W tym przykładzie
-b
i-c
(i ich długie formy--bravo
oraz--charlie
) mają obowiązkowe argumenty. Argumenty za długimi opcjami pojawiają się po znakach równości, np.--bravo=foo
(Ograniczniki spacji dla długich opcji byłyby trudne do wdrożenia, patrz poniżej).Ponieważ wykorzystuje to
getopts
wbudowane rozwiązanie, rozwiązanie to obsługuje takie jakcmd --bravo=foo -ac FILE
(które łączy opcje-a
i-c
przeplata długie opcje ze standardowymi opcjami), podczas gdy większość innych odpowiedzi tutaj walczy lub nie.Gdy opcją jest myślnik (
-
), jest to opcja długa.getopts
będzie parsował rzeczywistą długą opcję na$OPTARG
, np.--bravo=foo
oryginalne zestawyOPT='-'
iOPTARG='bravo=foo'
. Teif
zestawy stanza$OPT
do zawartości$OPTARG
przed pierwszym znakiem równości (bravo
w naszym przykładzie), a następnie usuwa, że od początku$OPTARG
(uzyskując=foo
w tym kroku, lub pusty ciąg jeśli nie jest=
). Wreszcie usuwamy wiodącą argumentację=
. W tym momencie$OPT
jest albo krótka opcja (jeden znak), albo długa opcja (ponad 2 znaki).case
Następnie dopasowuje albo krótkie lub długie opcje. W przypadku krótkich opcjigetopts
automatycznie narzeka na opcje i brakujące argumenty, dlatego musimy je replikować ręcznie za pomocąneeds_arg
funkcji, która kończy się, gdy$OPTARG
jest pusta.??*
Warunek będzie pasować do każdego pozostałego długiej opcji (?
dopasowuje pojedynczy znak i*
zero lub więcej, więc??*
pasuje 2+ znaków), co pozwala nam wydać opcję „Illegal” błąd przed wyjściem.(Uwaga na temat nazw zmiennych pisanych wielkimi literami: Ogólnie rzecz biorąc, radzę rezerwować zmienne pisane wielkimi literami do użytku systemowego. Zachowuję
$OPT
litery pisane wielkimi literami, aby zachować zgodność$OPTARG
, ale to łamie tę konwencję. Myślę, że pasuje, ponieważ jest to coś, co powinien był zrobić system, i powinno być bezpieczne, ponieważ nie ma żadnych standardów (afaik), które używają takiej zmiennej.)Aby narzekać na nieoczekiwane argumenty na długie opcje, naśladuj to, co zrobiliśmy dla argumentów obowiązkowych: użyj funkcji pomocnika. Po prostu odwróć test, aby narzekać na argument, którego się nie oczekuje:
Starsza wersja tej odpowiedzi miał próbę przyjmowanie długich opcji z argumentami spacjami, ale to nie było wiarygodne;
getopts
może przedwcześnie zakończyć działanie przy założeniu, że argument wykracza poza jego zakres, a ręczne zwiększanie$OPTIND
nie działa we wszystkich powłokach.Można to osiągnąć za pomocą jednej z następujących technik:
eval "bravo=\"\$$OPTIND\""
bravo="${!OPTIND}"
P
Zsh :bravo="${(P)OPTIND}"
a następnie zakończył czymś takim
[ $# -gt $OPTIND ] && OPTIND=$((OPTIND+1))
źródło
letter-c
nie wymaga argumentu, czy nie wystarczyłoby użyćletter-c)
?*
wydaje się zbędny.getopts
zatrzymuje się przy pierwszym argumencie pozycyjnym, ponieważ nie jest przeznaczony do radzenia sobie z nimi. Pozwala to na komendy podrzędne z własnymi argumentami, np.git diff --color
Interpretowałbym tocommand --foo=moo bar --baz waz
jako--foo
argument docommand
i--baz waz
jako argument (z opcją) do poleceniabar
podrzędnego. Można to zrobić za pomocą powyższego kodu. Odrzucam--bravo -blah
ponieważ--bravo
wymaga argumentu i nie jest jasne,-blah
czy nie jest to inna opcja.eval
powłoki POSIX, jest wymieniony poniżej reszty odpowiedzi.Spójrz na shFlags, która jest przenośną biblioteką powłoki (czyli: sh, bash, dash, ksh, zsh w Linux, Solaris itp.).
To sprawia, że dodawanie nowych flag jest tak proste, jak dodawanie jednej linii do skryptu, i zapewnia automatycznie generowaną funkcję użycia.
Oto prosty
Hello, world!
przy użyciu shFlag :W systemach operacyjnych z rozszerzoną funkcją getopt, która obsługuje długie opcje (np. Linux), możesz:
W pozostałym zakresie musisz użyć krótkiej opcji:
Dodanie nowej flagi jest tak proste, jak dodanie nowej
DEFINE_ call
.źródło
Używanie
getopts
z krótkimi / długimi opcjami i argumentamiDziała ze wszystkimi kombinacjami, np .:
Niektóre deklaracje dla tego przykładu
Jak wyglądałaby funkcja użycia
getops
z długimi / krótkimi flagami oraz długimi argumentamiWynik
Łącząc powyższe w spójny skrypt
źródło
eval
podejściem do argumentów z odstępami na długich opcjach i stwierdziłem, że jest niewiarygodne z niektórymi powłokami (choć spodziewam się, że będzie działać z bash, w którym to przypadku nie musisz używaćeval
). Zobacz moją odpowiedź, jak zaakceptować długie argumenty opcji=
i moje zanotowane próby użycia spacji. Moje rozwiązanie nie wykonuje połączeń zewnętrznych, podczas gdy to wykorzystujecut
kilka razy.Inny sposób...
źródło
$args
przeniesieniu? Można to zrobić nawet bez bzdur, ale ten kod straci spacje w opcjach i argumentach (nie sądzę, że$delim
sztuczka zadziała). Zamiast tego można uruchomićset
wewnątrz tejfor
pętli, jeśli jesteś na tyle ostrożny, aby opróżnić go tylko na pierwszej iteracji. Oto bezpieczniejsza wersja bez szaleństw.Rozwiązałem w ten sposób:
Czy jestem głupi czy coś takiego?
getopt
igetopts
są bardzo mylące.źródło
-ltr
lub-lt -r
równie dobrze-l -t -r
). Zapewnia również obsługę błędów i łatwy sposób na przesunięcie leczonych parametrów po zakończeniu leczenia opcjami.Jeśli nie chcesz
getopt
zależności, możesz to zrobić:Oczywiście nie możesz użyć opcji długiego stylu za pomocą jednego myślnika. A jeśli chcesz dodać skrócone wersje (np. --Verbos zamiast --verbose), musisz dodać je ręcznie.
Ale jeśli chcesz uzyskać
getopts
funkcjonalność wraz z długimi opcjami, jest to prosty sposób na zrobienie tego.Ten fragment kodu również umieszczam w treści .
źródło
--)
wydaje się, żeshift ;
brakuje. W tej chwili--
pozostanie jako pierwszy argument bez opcji.--
opcja wymagashift
tam. Mówię to jest lepiej, bo alternatywy są albo platforma wersje Zależnagetopt
lubgetopts_long
czy trzeba wymusić zwarć opcje mają być używane tylko na początku polecenia (czyli - użyćgetopts
następnie przetwarzać długie opcje później), a to daje każde zamówienie i pełną kontrolę.Wbudowane
getopts
nie może tego zrobić. Istnieje zewnętrzny program getopt (1), który może to zrobić, ale można go uzyskać tylko w systemie Linux z pakietu util-linux . Jest wyposażony w przykładowy skrypt getopt-parse.bash .Jest też
getopts_long
napisana jako funkcja powłoki.źródło
getopt
Została ujęta w FreeBSD w wersji 1.0 w 1993 roku i jest częścią FreeBSD od tamtego czasu. Jako taki został przyjęty z FreeBSD 4.x do włączenia do projektu Apple Darwin. Począwszy od OS X 10.6.8, strona podręcznika dołączona przez Apple pozostaje dokładnym duplikatem strony podręcznika FreeBSD. Tak, to jest zawarte w OS X i gobach innych systemów operacyjnych oprócz Linuksa. -1 w tej odpowiedzi za dezinformację..
źródło
"${1:0:1}"
argumentu 1, podłańcucha o indeksie 0, długości 1. Nie pozwala to na mieszanie krótkich i długich opcji.W
ksh93
,getopts
obsługuje długie nazwy ...Tak powiedziano w samouczkach, które znalazłem. Wypróbuj i przekonaj się.
źródło
Piszę tylko od czasu do czasu skrypty powłoki i wypadam z praktyki, więc wszelkie uwagi są mile widziane.
Korzystając ze strategii zaproponowanej przez @Arvid Requate, zauważyliśmy błędy użytkowników. Użytkownik, który zapomni podać wartość, przypadkowo będzie traktował nazwę następnej opcji jako wartość:
spowoduje, że wartość „loglevel” będzie postrzegana jako „--toc = TRUE”. Można tego uniknąć.
Dostosowałem kilka pomysłów na temat sprawdzania błędów użytkownika w interfejsie CLI na podstawie http://mwiki.wooledge.org/BashFAQ/035 dyskusji na temat ręcznego analizowania. Włączyłem sprawdzanie błędów do obsługi argumentów „-” i „-”.
Potem zacząłem majstrować przy składni, więc wszelkie błędy tutaj są wyłącznie moją winą, a nie oryginalnymi autorami.
Moje podejście pomaga użytkownikom, którzy wolą długo wchodzić z lub bez znaku równości. Oznacza to, że powinna mieć taką samą odpowiedź na „--loglevel 9” jak „--loglevel = 9”. W metodzie - / space nie ma pewności, czy użytkownik zapomni argumentu, dlatego konieczne jest pewne odgadnięcie.
Jeśli zaczynasz od tego, istnieje interesująca różnica między formatami „--opt = wartość” i „--opt wartość”. W przypadku znaku równości argument wiersza poleceń jest postrzegany jako „opt = wartość”, a praca do przetworzenia polegająca na analizie ciągów znaków, w celu rozdzielenia na „=”. W przeciwieństwie do „--opt value” nazwa argumentu to „opt” i mamy problem z uzyskaniem następnej wartości podanej w wierszu poleceń. To tutaj @Arvid Requate zastosowało $ {! OPTIND}, odniesienie pośrednie. Wciąż tego nie rozumiem, a komentarze w BashFAQ wydają się ostrzegać przed tym stylem ( http://mywiki.wooledge.org/BashFAQ/006 ). BTW, nie sądzę, aby komentarze poprzedniego autora dotyczące ważności OPTIND = $ ((OPTIND + 1)) były poprawne. Mam na myśli powiedzieć
W najnowszej wersji tego skryptu flaga -v oznacza wydruk VERBOSE.
Zapisz go w pliku o nazwie „cli-5.sh”, włącz plik wykonywalny, a dowolny z nich będzie działał lub zawiedzie w pożądany sposób
Oto przykład danych wyjściowych sprawdzania błędów w intpu użytkownika
Powinieneś rozważyć włączenie opcji -v, ponieważ wypisuje ona elementy wewnętrzne OPTIND i OPTARG
źródło
OPTIND=$(( $OPTIND + 1 ))
: jest potrzebny za każdym razem, gdy „pożerasz” parametr OPTIND (na przykład: kiedy jeden użyty--toc value
: wartość znajduje się w parametrze o numerze $ OPTIND. Po odzyskaniu go dla wartości toc powinieneś powiedzieć getopts, że następny parametr do przeanalizowania nie jest wartością, ale brakuje jednego po nim (stąd:.OPTIND=$(( $OPTIND + 1 ))
i twój skrypt (jak również skrypt, do którego się odwołujesz), po zakończeniu:shift $(( $OPTIND -1 ))
(gdy getopts zakończył pracę po analizie parametrów 1 do OPTIND-1, musisz je przesunąć, aby$@
są teraz wszelkie pozostałe parametry „inne niż opcje”Wymyślenie kolejnej wersji koła ...
Ta funkcja jest (mam nadzieję) zgodnym z POSIX zamiennikiem powłoki bourne dla GNU getopt. Obsługuje krótkie / długie opcje, które mogą przyjmować argumenty obowiązkowe / opcjonalne / brak, a sposób ich określania jest prawie identyczny z GNU getopt, więc konwersja jest banalna.
Oczywiście jest to nadal znaczna część kodu do umieszczenia w skrypcie, ale jest to około połowa linii dobrze znanej funkcji powłoki getopt_long, i może być lepsza w przypadkach, gdy chcesz po prostu zastąpić istniejące zastosowania GNU getopt.
To całkiem nowy kod, więc YMMV (i zdecydowanie daj mi znać, jeśli z jakiegoś powodu nie jest on w rzeczywistości zgodny z POSIX - od samego początku chodziło o przenośność, ale nie mam przydatnego środowiska testowego POSIX).
Następujące użycie kodu i przykładu:
Przykładowe użycie:
źródło
Przyjęta odpowiedź bardzo dobrze pokazuje wszystkie niedociągnięcia wbudowanego basha
getopts
. Odpowiedź kończy się na:I chociaż zasadniczo zgadzam się z tym stwierdzeniem, wydaje mi się, że liczba przypadków, w których wszyscy zaimplementowaliśmy tę funkcję w różnych skryptach, uzasadnia włożenie wysiłku w stworzenie „znormalizowanego”, dobrze przetestowanego rozwiązania.
Jako taki „zaktualizowałem” bash wbudowany
getopts
poprzez implementacjęgetopts_long
w czystym bashu, bez zewnętrznych zależności. Korzystanie z funkcji jest w 100% zgodne z wbudowanymgetopts
.Uwzględniając
getopts_long
(który jest hostowany na GitHub ) w skrypcie, odpowiedź na pierwotne pytanie można zaimplementować tak prosto, jak:źródło
Nie mam jeszcze wystarczającej liczby przedstawicieli, aby skomentować lub zagłosować na jego rozwiązanie, ale odpowiedź Sme działała dla mnie wyjątkowo dobrze. Jedynym problemem, na jaki natknąłem się, było to, że argumenty zostały zamknięte w pojedyncze cudzysłowy (więc mam je rozebrać).
Dodałem także przykładowe zastosowania i tekst POMOCY. Zamieszczę tutaj moją nieco rozszerzoną wersję:
źródło
Tutaj możesz znaleźć kilka różnych metod analizy złożonych opcji w bash: http://mywiki.wooledge.org/ComplexOptionParsing
Stworzyłem następujący i myślę, że jest dobry, ponieważ jest to minimalny kod oraz działają długie i krótkie opcje. Długa opcja może mieć wiele argumentów przy takim podejściu.
źródło
Pracuję nad tym tematem od dłuższego czasu ... i stworzyłem własną bibliotekę, którą będziecie musieli zdobyć w głównym skrypcie. Zobacz na przykład libopt4shell i cd2mpc . Mam nadzieję, że to pomoże !
źródło
Ulepszone rozwiązanie:
źródło
Być może łatwiej jest użyć ksh, tylko dla części getopts, jeśli potrzebujesz długich opcji wiersza poleceń, ponieważ można to łatwiej zrobić.
źródło
Chciałem czegoś bez zewnętrznych zależności, ze ścisłą obsługą bash (-u) i potrzebowałem go do pracy nawet ze starszymi wersjami bash. To obsługuje różne typy parametrów:
Po prostu wstaw następujące elementy u góry skryptu:
I użyj go w ten sposób:
źródło
Aby zachować zgodność między platformami i uniknąć polegania na zewnętrznych plikach wykonywalnych, przeniosłem trochę kodu z innego języka.
Uważam, że jest bardzo łatwy w użyciu, oto przykład:
Wymagana BASH jest trochę dłuższa niż mogłaby być, ale chciałem uniknąć polegania na tablicach asocjacyjnych BASH 4. Możesz go również pobrać bezpośrednio ze strony http://nt4.com/bash/argparser.inc.sh
źródło
Jeśli wszystkie długie opcje mają unikalne i dopasowane, pierwsze znaki jako krótkie opcje, na przykład
Jest taki sam jak
Możesz użyć tego przed getopts, aby przepisać $ args:
Dzięki za mtvee za inspirację ;-)
źródło
jeśli po prostu tak chcesz wywołać skrypt
następnie możesz zastosować ten najprostszy sposób, aby to osiągnąć za pomocą getopt i --longoptions
spróbuj tego, mam nadzieję, że to się przyda
źródło
getopts „może być użyty” do analizowania długich opcji, o ile nie oczekujesz, że będą miały argumenty ...
Oto jak:
Jeśli spróbujesz użyć OPTIND do uzyskania parametru dla długiej opcji, getopts potraktuje go jako pierwszy brak opcjonalnego parametru pozycyjnego i przestanie analizować inne parametry. W takim przypadku lepiej będzie obsługiwać go ręcznie za pomocą prostego opisu sprawy.
To zawsze będzie działać:
Chociaż nie jest tak elastyczny jak getopts i musisz sam zrobić wiele kodu sprawdzania błędów w instancjach sprawy ...
Ale to jest opcja.
źródło
Wbudowane
getopts
analizują tylko krótkie opcje (z wyjątkiem ksh93), ale nadal możesz dodać kilka wierszy skryptów, aby getopts obsługiwał długie opcje.Oto część kodu znaleziona w http://www.uxora.com/unix/shell-script/22-handle-long-options-with-getopts
Oto test:
W przeciwnym razie w najnowszej wersji Ksh Shell ksh93
getopts
można oczywiście analizować długie opcje, a nawet wyświetlać stronę podręcznika. (Zobacz http://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options )źródło
Th wbudowany w OS X (BSD) getopt nie obsługuje długich opcji, ale w wersji GNU robi:
brew install gnu-getopt
. Potem coś podobnego do:cp /usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt /usr/local/bin/gnu-getopt
.źródło
EasyOptions obsługuje krótkie i długie opcje:
źródło