Powiedzmy, że mam skrypt wywoływany za pomocą tej linii:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
albo ten:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Co znajduje się w przyjętym sposobem analizowania tego taki, że w każdym przypadku (lub kombinacja tych dwóch) $v
, $f
i $d
wszystko będzie ustawiona true
i $outFile
będzie równa /fizz/someOtherFile
?
zparseopts -D -E -M -- d=debug -debug=d
I mieć oba,-d
a--debug
w$debug
tablicyecho $+debug[1]
zwróci 0 lub 1, jeśli jeden z nich zostanie użyty. Ref: zsh.org/mla/users/2011/msg00350.htmlOdpowiedzi:
Metoda nr 1: Używanie bash bez getopt [s]
Dwa typowe sposoby przekazywania argumentów para klucz-wartość to:
Bash Rozdzielone spacjami (np.
--option argument
) (Bez getopt [s])Stosowanie
demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts
wynik z kopiowania i wklejenia powyższego bloku:
Bash Equals-Separated (np.
--option=argument
) (Bez getopt [s])Stosowanie
demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts
wynik z kopiowania i wklejenia powyższego bloku:
Aby lepiej zrozumieć,
${i#*=}
wyszukaj „Usuwanie podciągów” w tym przewodniku . Jest funkcjonalnie równoważny z tym,`sed 's/[^=]*=//' <<< "$i"`
które wywołuje niepotrzebny podproces lub`echo "$i" | sed 's/[^=]*=//'`
które wywołuje dwa niepotrzebne podprocesy.Metoda nr 2: Używanie bash z getopt [s]
from: http://mywiki.wooledge.org/BashFAQ/035#getopts
ograniczenia getopt (1) (starsze, stosunkowo nowe
getopt
wersje):Nowsze
getopt
wersje nie mają tych ograniczeń.Dodatkowo oferta powłoki POSIX (i innych),
getopts
która nie ma tych ograniczeń. Podałem uproszczonygetopts
przykład.Stosowanie
demo-getopts.sh -vf /etc/hosts foo bar
wynik z kopiowania i wklejenia powyższego bloku:
Zalety
getopts
to:dash
.-vf filename
typowy system uniksowy.Wadą
getopts
jest to, że może obsługiwać tylko krótkie opcje (-h
nie--help
) bez dodatkowego kodu.Istnieje samouczek Getopts, który wyjaśnia, co oznacza cała składnia i zmienne. W bash jest też coś
help getopts
, co może być pouczające.źródło
getopt
która zawiera wszystkie funkcje,getopts
a następnie niektóre.man getopt
na wyjściach Ubuntu 13.04getopt - parse command options (enhanced)
jako nazwa, więc zakładam, że ta ulepszona wersja jest teraz standardem.getopt
nie jest narzędziem GNU, jest częściąutil-linux
.-gt 0
, usuńshift
poesac
, zwiększ wszystkieshift
o 1 i dodaj ten przypadek:*) break;;
możesz obsłużyć argumenty nieopcjonalne. Np .: pastebin.com/6DJ57HTc–default
. W pierwszym przykładzie zauważam, że jeśli–default
jest ostatnim argumentem, nie jest przetwarzany (uważany za non-opt), chyba żewhile [[ $# -gt 1 ]]
jest ustawiony jakowhile [[ $# -gt 0 ]]
Brak odpowiedzi wspomina o ulepszonym getopt . A najczęściej głosowana odpowiedź jest myląca: ignoruje
-vfd
krótkie opcje stylu (wymagane przez PO) lub opcje po argumentach pozycyjnych (również wymagane przez OP); i ignoruje błędy parsowania. Zamiast:getopt
z util-linux lub wcześniej GNU glibc . 1getopt_long()
funkcją C GNU glibc.getopt
jest to możliwe bez rozszerzenia )script.sh -o outFile file1 file2 -v
(getopts
nie robi tego)=
-Style długie opcje:script.sh --outfile=fileOut --infile fileIn
(pozwalając obu jest długa, jeśli własny parsowania)-vfd
(prawdziwa praca, jeśli parsuje się)-oOutfile
lub-vfdoOutfile
getopt --test
→ zwracanej wartości 4.getopt
lub wbudowane powłokigetopts
mają ograniczone zastosowanie.Następujące połączenia
wszyscy wracają
z następującymi
myscript
1 ulepszony getopt jest dostępny na większości „systemów bash”, w tym Cygwin; w systemie OS X spróbuj zainstalować gnu-getopt lub
sudo port install getopt
2,
exec()
konwencjePOSIXnie mają niezawodnego sposobu na przekazanie binarnej wartości NULL w argumentach wiersza poleceń; te bajty przedwcześnie kończąpierwszą wersjęargumentu3 wydaną w 1997 r. lub wcześniej (prześledziłem ją tylko do 1997 r.)
źródło
getopt
jest to najlepsza droga.getopt
jest to, że nie można go wygodnie używać w skryptach opakowujących, w których można mieć kilka opcji specyficznych dla skryptu opakowującego, a następnie przekazać opcje spoza skryptu opakowującemu plik wykonywalny w stanie nienaruszonym. Powiedzmy, że mamgrep
wywołanie otokimygrep
i mam opcję--foo
specyficzną dlamygrep
, wtedy nie mogę tego zrobićmygrep --foo -A 2
, i mam to-A 2
automatycznie przekazanegrep
; I trzeba to zrobićmygrep --foo -- -A 2
. Oto moje wdrożenie na szczycie twojego rozwiązania.man bash
Bardziej zwięzły sposób
script.sh
Stosowanie:
źródło
while [[ "$#" > 1 ]]
jeśli chcę wesprzeć zakończenie linii flagą logiczną./script.sh --debug dev --uglify fast --verbose
. Przykład: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58./script.sh -d dev -d prod
spowodowałobydeploy == 'prod'
. I tak go użyłem: P :): +1:./script.sh -d
Nie generowałby błędu, a po prostu ustawiał$deploy
pusty ciąg.from: digitalpeer.com z niewielkimi modyfikacjami
Stosowanie
myscript.sh -p=my_prefix -s=dirname -l=libname
Aby lepiej zrozumieć,
${i#*=}
wyszukaj „Usuwanie podciągów” w tym przewodniku . Jest funkcjonalnie równoważny z tym,`sed 's/[^=]*=//' <<< "$i"`
które wywołuje niepotrzebny podproces lub`echo "$i" | sed 's/[^=]*=//'`
które wywołuje dwa niepotrzebne podprocesy.źródło
mount -t tempfs ...
. Prawdopodobnie można to naprawić za pomocą czegoś podobnegowhile [ $# -ge 1 ]; do param=$1; shift; case $param in; -p) prefix=$1; shift;;
itp.-vfd
połączonymi krótkimi opcjami stylu.getopt()
/getopts()
to dobra opcja. Skradziono stąd :źródło
$*
to nieprawidłowe użyciegetopt
. (Węży argumenty ze spacjami.) Zobacz moją odpowiedź dla właściwego użycia.Na ryzyko dodania kolejnego przykładu do zignorowania, oto mój schemat.
-n arg
i--name=arg
Mam nadzieję, że komuś się przyda.
źródło
*) die "unrecognized argument: $1"
lub zebrać argumenty do zmiennej*) args+="$1"; shift 1;;
.shift 2
, wydającshift
dwa razy zamiastshift 2
. Sugerowana edycja.Spóźniłem się z tym pytaniem około 4 lat, ale chcę się zrewanżować. Użyłem wcześniejszych odpowiedzi jako punktu wyjścia do uporządkowania mojej starej analizy adhoc param. Następnie dokonałem refaktoryzacji następującego kodu szablonu. Obsługuje zarówno długie, jak i krótkie parametry, używając argumentów = lub oddzielonych spacjami, a także wiele krótkich parametrów zgrupowanych razem. Wreszcie ponownie wstawia argumenty nieparametrowe z powrotem do zmiennych $ 1, $ 2 .. Mam nadzieję, że to się przyda.
źródło
-c1
. A użycie=
oddzielenia krótkich opcji od ich argumentów jest niezwykłe ...Znalazłem problem z pisaniem przenośnego parsowania w skryptach tak frustrujący, że napisałem Argbash - generator kodu FOSS, który może generować kod parsujący argumenty dla twojego skryptu i ma kilka fajnych funkcji:
https://argbash.io
źródło
Moja odpowiedź w dużej mierze opiera się na odpowiedzi Brunona Bronosky'ego , ale w pewnym sensie zmiksowałem jego dwie implementacje czystego basha w jedną, z której dość często korzystam.
To pozwala mieć zarówno opcje / wartości oddzielone spacjami, jak i równe zdefiniowane wartości.
Abyś mógł uruchomić skrypt za pomocą:
jak również:
i oba powinny mieć ten sam efekt końcowy.
Plusy:
Pozwala zarówno na -arg = wartość, jak i -arg wartość
Działa z dowolną nazwą argumentu, której można użyć w bash
Pure Bash. Nie musisz się uczyć / używać getopt ani getopts
CONS:
Nie można łączyć argumentów
Są to jedyne zalety / wady, które mogę wymyślić z góry
źródło
Myślę, że ten jest wystarczająco prosty w użyciu:
Przykład wywołania:
źródło
-a=1
jako stylu argc. Wolę umieścić najpierw główną opcję - opcje, a później te specjalne z pojedynczymi odstępami-o option
. Szukam najprostszego vs lepszego sposobu na czytanie argumentów../myscript -v -d fail -o /fizz/someOtherFile -f ./foo/bar/someFile
własnym skryptem. -d opcja nie jest ustawiona jako d:Rozwijając doskonałą odpowiedź @ guneysus, oto poprawka, która pozwala użytkownikowi na użycie dowolnej składni, którą preferują, np.
vs
To znaczy, że równe można zastąpić białymi spacjami.
Ta „rozmyta interpretacja” może Ci się nie podobać, ale jeśli tworzysz skrypty, które są wymienne z innymi narzędziami (tak jak w przypadku mojego, który musi współpracować z ffmpeg), elastyczność jest przydatna.
źródło
Ten przykład pokazuje, jak używać
getopt
ieval
iHEREDOC
ishift
obsługiwać krótkich i długich parametrów bez wymaganej wartości, które obserwuje. Również instrukcja zamiany / sprawy jest zwięzła i łatwa do naśladowania.Najważniejsze wiersze powyższego skryptu to:
Krótko, do rzeczy, czytelny i obsługuje prawie wszystko (IMHO).
Mam nadzieję, że komuś pomoże.
źródło
Daję ci funkcję,
parse_params
która będzie analizować parametry z linii poleceń.--all
równa się-all
równa sięall=all
)Poniższy skrypt jest działającą demonstracją kopiuj-wklej. Zobacz
show_use
funkcję, aby zrozumieć, jak używaćparse_params
.Ograniczenia:
-d 1
)--any-param
i-anyparam
będą równoważneeval $(parse_params "$@")
musi być używany wewnątrz funkcji bash (nie będzie działać w zakresie globalnym)źródło
show_use "$@"
EasyOptions nie wymaga analizowania:
źródło
getopts działa świetnie, jeśli # 1 masz go zainstalowanego i # 2 zamierzasz go uruchomić na tej samej platformie. Na przykład OSX i Linux zachowują się inaczej.
Oto rozwiązanie (nie getopts), które obsługuje flagi równości, nierówności i wartości logiczne. Na przykład możesz uruchomić skrypt w następujący sposób:
źródło
Tak właśnie robię w funkcji, aby uniknąć przerywania uruchamiania getopts jednocześnie gdzieś wyżej na stosie:
źródło
Rozwijając odpowiedź @ bruno-bronosky, dodałem „preprocesor” do obsługi niektórych popularnych formatowań:
--longopt=val
w--longopt val
-xyz
w-x -y -z
--
wskazanie końca flagźródło
Istnieje kilka sposobów parsowania argumentów cmdline (np. GNU getopt (nieprzenośny) vs BSD (OSX) getopt vs getopts) - wszystkie są problematyczne. To rozwiązanie jest
=
separatora-vxf
Przykłady: dowolny z
źródło
Chciałbym zaoferować moją wersję analizy składni opcji, która umożliwia:
Pozwala również na to (może być niepożądane):
Przed użyciem musisz zdecydować, czy w opcji ma być użyte =, czy nie. Ma to na celu utrzymanie kodu w czystości (ish).
źródło
Rozwiązanie, które zachowuje nieobsługiwane argumenty. Dema w zestawie.
Oto moje rozwiązanie. Jest BARDZO elastyczny i w przeciwieństwie do innych, nie powinien wymagać zewnętrznych pakietów i bez problemu radzi sobie z pozostałymi argumentami.
Zastosowanie to:
./myscript -flag flagvariable -otherflag flagvar2
Wszystko, co musisz zrobić, to edytować linię validflags. Przygotowuje łącznik i przeszukuje wszystkie argumenty. Następnie definiuje następny argument jako nazwę flagi, np
Główny kod (krótka wersja, pełne dalszych przykładów, także wersja z błędami):
Pełna wersja z wbudowanymi demami echa:
Ostatni, ten popełni błąd, jeśli zostanie przekazany nieprawidłowy instrument.
Plusy: co robi, radzi sobie bardzo dobrze. Zachowuje nieużywane argumenty, których nie ma w wielu innych rozwiązaniach. Pozwala także na wywoływanie zmiennych bez ręcznego definiowania w skrypcie. Pozwala również na wstępne wypełnienie zmiennych, jeśli nie podano odpowiedniego argumentu. (Zobacz pełny przykład).
Wady: Nie można przeanalizować pojedynczego złożonego ciągu arg, np. -Xcvf przetworzyłby jako pojedynczy argument. Możesz jednak dość łatwo napisać dodatkowy kod do mojego, który dodaje tę funkcjonalność.
źródło
Chcę przesłać mój projekt: https://github.com/flyingangel/argparser
Proste. Środowisko zostanie wypełnione zmiennymi o takiej samej nazwie jak argumenty
źródło
Zauważ, że
getopt(1)
był to krótkotrwały błąd AT&T.getopt powstał w 1984 roku, ale został pochowany w 1986 roku, ponieważ tak naprawdę nie był użyteczny.
Dowodem na to, że
getopt
jest bardzo nieaktualna, jest to, żegetopt(1)
strona podręcznika nadal wspomina o tym,"$*"
zamiast tego"$@"
, że została dodana do Bourne Shell w 1986 roku wraz zgetopts(1)
wbudowaną powłoką, aby poradzić sobie z argumentami ze spacjami w środku.BTW: jeśli jesteś zainteresowany analizowaniem długich opcji w skryptach powłoki, interesujące może być to, że
getopt(3)
implementacja z libc (Solaris) iksh93
obie dodały jednolitą długą implementację opcji, która obsługuje długie opcje jako aliasy dla krótkich opcji. To powodujeksh93
iBourne Shell
zaimplementowanie jednolitego interfejsu dla długich opcji poprzezgetopts
.Przykład długich opcji ze strony podręcznika Bourne Shell:
getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"
pokazuje, jak długo aliasy opcji mogą być używane zarówno w Bourne Shell, jak i ksh93.
Zobacz stronę manuala ostatniej powłoki Bourne'a:
http://schillix.sourceforge.net/man/man1/bosh.1.html
oraz strona man dla getopt (3) z OpenSolaris:
http://schillix.sourceforge.net/man/man3c/getopt.3c.html
i na koniec strona podręcznika getopt (1) w celu weryfikacji nieaktualnej $ *:
http://schillix.sourceforge.net/man/man1/getopt.1.html
źródło
Napisałem pomocnika bash, aby napisać ładne narzędzie bash
strona projektu: https://gitlab.mbedsys.org/mbedsys/bashopts
przykład:
udzieli pomocy:
cieszyć się :)
źródło
Oto moje podejście - użycie wyrażenia regularnego.
-qwerty
-q -w -e
--qwerty
=
do podania atrybutów, ale dopasowanie atrybutów do momentu napotkania łącznika + spacja „separator”, więc w--q=qwe ty
qwe ty
jest jeden atrybut-o a -op attr ibute --option=att ribu te --op-tion attribute --option att-ribute
jest poprawnyscenariusz:
źródło
Załóżmy, że tworzymy skrypt powłoki o nazwie
test_args.sh
następującoPo uruchomieniu następującego polecenia:
Dane wyjściowe będą:
źródło
Użyj „argumentów” modułu z bash-modułów
Przykład:
źródło
Mieszanie argumentów pozycyjnych i opartych na flagach
--param = arg (równa się ograniczeniom)
Dowolne mieszanie flag między argumentami pozycyjnymi:
można to osiągnąć dość zwięźle:
--param arg (rozdzielany spacją)
Zwykle łatwiej jest nie mieszać
--flag=value
i--flag value
stylizować.Jest to trochę ryzykowne do przeczytania, ale nadal jest ważne
Źródło
źródło
Oto getopts, który osiąga parsowanie przy minimalnym kodzie i pozwala zdefiniować, co chcesz wyodrębnić w jednym przypadku za pomocą eval z podciągiem.
Gruntownie
eval "local key='val'"
Deklaruje zmienne jako lokalne zamiast globalne, jak większość odpowiedzi tutaj.
Nazywany jako:
$ {K: 3} jest w zasadzie podciągiem do usunięcia pierwszego
---
z klucza.źródło
Warto również wiedzieć, że możesz ustawić wartość, a jeśli ktoś dostarczy dane wejściowe, zastąp wartość domyślną tą wartością.
myscript.sh -f ./serverlist.txt lub po prostu ./myscript.sh (i to zajmuje wartości domyślne)
źródło
Inne rozwiązanie bez getopt [s], POSIX, stary styl uniksowy
Podobne do rozwiązania, które Bruno Bronosky opublikował tutaj, to jedno bez użycia
getopt(s)
.Główną cechą odróżniającą moje rozwiązanie jest to, że pozwala na łączenie opcji tak samo, jak
tar -xzf foo.tar.gz
jest równetar -x -z -f foo.tar.gz
. I podobnie jak wtar
,ps
itp wiodącym myślnik jest opcjonalne dla bloku krótkich opcji (ale to można łatwo zmienić). Obsługiwane są również długie opcje (ale gdy blok zaczyna się od jednego, wówczas wymagane są dwa wiodące myślniki).Kod z przykładowymi opcjami
Aby zapoznać się z przykładem użycia, zobacz przykłady poniżej.
Pozycja opcji z argumentami
Na ile warto, opcje z argumentami nie są ostatnie (muszą być tylko długie opcje). Tak więc chociaż np. W
tar
(przynajmniej w niektórych implementacjach)f
opcje muszą być ostatnie, ponieważ nazwa pliku następuje (tar xzf bar.tar.gz
działa, aletar xfz bar.tar.gz
nie działa), tutaj tak nie jest (patrz późniejsze przykłady).Wiele opcji z argumentami
Jako kolejny bonus parametry opcji są zużywane w kolejności opcji według parametrów z wymaganymi opcjami. Wystarczy spojrzeć na wyniki mojego skryptu tutaj za pomocą wiersza poleceń
abc X Y Z
(lub-abc X Y Z
):Połączono także długie opcje
Możesz także mieć długie opcje w bloku opcji, biorąc pod uwagę, że występują one na końcu bloku. Zatem wszystkie poniższe wiersze poleceń są równoważne (w tym kolejność przetwarzania opcji i jej argumentów):
-cba Z Y X
cba Z Y X
-cb-aaa-0-args Z Y X
-c-bbb-1-args Z Y X -a
--ccc-2-args Z Y -ba X
c Z Y b X a
-c Z Y -b X -a
--ccc-2-args Z Y --bbb-1-args X --aaa-0-args
Wszystko to prowadzi do:
Nie w tym rozwiązaniu
Opcjonalne argumenty
Opcje z opcjonalnymi argumentami powinny być możliwe przy odrobinie pracy, np. Przez sprawdzenie, czy istnieje blok bez myślnika; użytkownik musiałby wtedy wstawić łącznik przed każdym blokiem po bloku z parametrem mającym parametr opcjonalny. Być może jest to zbyt skomplikowane, aby komunikować się z użytkownikiem, dlatego lepiej w tym przypadku po prostu wymagać łącznika wiodącego.
Sprawa staje się jeszcze bardziej skomplikowana dzięki wielu możliwym parametrom. Odradzałbym, aby opcje próbowały być sprytne, określając, czy argument może być za nim, czy nie (np. Z opcją po prostu bierze liczbę jako argument opcjonalny), ponieważ może się to złamać w przyszłości.
Osobiście preferuję dodatkowe opcje zamiast opcjonalnych argumentów.
Argumenty opcji wprowadzone ze znakiem równości
Podobnie jak w przypadku opcjonalnych argumentów, nie jestem tego fanem (BTW, czy istnieje wątek omawiania zalet / wad różnych stylów parametrów?), Ale jeśli tego chcesz, prawdopodobnie możesz go zaimplementować samodzielnie, tak jak na stronie http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop z
--long-with-arg=?*
instrukcją case, a następnie usuwając znak równości (jest to BTW strona, która mówi, że dokonanie konkatenacji parametrów jest możliwe z pewnym wysiłkiem, ale „pozostawiono [it] jako ćwiczenie dla czytelnika „co sprawiło, że uwierzyłem im na słowo, ale zacząłem od zera).Inne notatki
POSIX, działa nawet na starożytnych BusyBox konfiguracji miałem do czynienia z (z np
cut
,head
igetopts
brakuje).źródło