Nie wiem, jak dołączyć opcjonalne argumenty / flagi podczas pisania skryptu bash dla następującego programu:
Program wymaga dwóch argumentów:
run_program --flag1 <value> --flag2 <value>
Istnieje jednak kilka opcjonalnych flag:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
Chciałbym uruchomić skrypt bash, aby pobierał argumenty użytkownika. Jeśli użytkownicy wprowadzą tylko dwa argumenty w kolejności, będzie to:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
Ale co, jeśli uwzględniony zostanie którykolwiek z opcjonalnych argumentów? Myślałbym, że tak będzie
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
Ale co, jeśli podano 4 USD, ale nie 3 USD?
shell-script
arguments
ShanZhengYang
źródło
źródło
getopts
jest tym, czego chcesz. Bez tego można użyć pętli z instrukcją switch do wykrycia każdej flagi, opcjonalnie lub nie.getopts
, musiałbym podać każdą kombinację argumentów? 3 i 4, 3 i 5, 3 i 4 i 5 itd.?getopts
. Powiedzmy, że zmuszam użytkowników do uruchomienia skryptu ze wszystkimi argumentami:run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE
który uruchamia program jakoprogram --flag1 VAL --flag2 VAL
. Jeśli uruchomiłeśrun_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE
, program działałby jakoprogram --flag1 VAL --flag2 VAL --optflag2 10
. Jak możesz uzyskać takie zachowaniegetopts
?Odpowiedzi:
Ten artykuł pokazuje dwa różne sposoby -
shift
orazgetopts
(i omawia zalety i wady obu podejść).Ze
shift
swoim wyglądem skryptu,$1
decyduje, jakie działania podjąć, a następnie wykonujeshift
, przesuwając$2
się$1
,$3
aby$2
itdNa przykład:
Po
getopts
zdefiniowaniu (krótkich) opcji wwhile
wyrażeniu:Oczywiście są to tylko fragmenty kodu i pominąłem sprawdzanie poprawności - sprawdzanie, czy ustawiono obowiązkowe argumenty flag1 i flag2 itd.
Które podejście jest do pewnego stopnia kwestią gustu - jak przenośny ma być twój skrypt, czy możesz żyć tylko z krótkimi (POSIX) opcjami, czy chcesz długimi (GNU) opcjami itp.
źródło
while (( $# ))
zamiastwhile :;
i często rezygnuję z błędu w*
sprawieset -o nounset
pierwszego rozwiązania wystąpi błąd, jeśli nie zostanie podany żaden parametr. Poprawka:case ${1:-} in
użyj tablicy.
to poprawnie obsłuży argumenty ze spacjami.
[edytuj] Użyłem z grubsza równoważnej składni,
args=( "${args[@]}" --optflag1 "$3" )
ale G-Man zaproponował lepszy sposób.źródło
args+=( --optflag1 "$3" )
. Być może chciałbyś zobaczyć moją odpowiedź na naszą pracę referencyjną, Implikacje bezpieczeństwa wynikające z niezapisania zmiennej w powłokach bash / POSIX , gdzie omawiam tę technikę (budowanie wiersza poleceń w tablicy przez warunkowe dołączanie opcjonalnych argumentów).[@]
że mam wystarczające narzędzie do rozwiązania mojego problemu.W skrypcie powłoki argumentami są „$ 1”, „$ 2”, „$ 3” itd. Liczba argumentów to $ #.
Jeśli twój skrypt nie rozpoznaje opcji, możesz pominąć wykrywanie opcji i traktować wszystkie argumenty jako operandy.
Aby rozpoznać opcje, użyj wbudowanego getopts
źródło
Jeśli twoje opcje wprowadzania są pozycyjne (wiesz, w których miejscach się znajdują), a nie są oznaczone flagami, to po prostu zbuduj linię poleceń. Po prostu przygotuj argumenty poleceń dla wszystkich:
Jeśli parametry nie są określone, odpowiednie ciągi są puste i rozwijają się w nic. Zauważ, że w ostatnim wierszu nie ma cudzysłowów. Jest tak, ponieważ chcesz, aby powłoka podzieliła parametry na słowa (aby podać
--flag1
i$1
jako osobne argumenty dla twojego programu). Oczywiście pójdzie to źle, jeśli oryginalne parametry zawierają spacje. Jeśli to ty go uruchamiasz, możesz to zostawić, ale jeśli jest to ogólny skrypt, może mieć nieoczekiwane zachowanie, jeśli użytkownik wprowadzi coś ze spacjami. Aby sobie z tym poradzić, musisz uczynić kod nieco brzydszym.x
Prefiks w[]
teście istnieje w przypadku$3
lub$4
jest pusta. W takim przypadku bash rozwinąłby się[ FALSE != $3 ]
w[ FALSE != ]
błąd składniowy, więc istnieje inny arbitralny znak, aby się przed tym uchronić. Jest to bardzo powszechny sposób, zobaczysz go w wielu skryptach.Ustawiłem
OPTFLAG1
i resztę""
na początek, żeby się upewnić (na wypadek, gdyby coś wcześniej było ustawione), ale jeśli tak naprawdę nie zostały zadeklarowane w środowisku, to nie musisz tego robić.Kilka dodatkowych uwag:
runprogram
robi: z flagami. O tymJohn N
mówi. Tamgetopts
staje się przydatne.-
) do zasygnalizowania pustej wartości lub po prostu przekazuje pusty ciąg znaków, na przykład""
, jeśli nie jest to poprawna wartość parametru. Pusty ciąg powoduje również, że test jest krótszy, wystarczy użyćif [ -n "$3" ]
.""
pustych parametrów, jak sugerowano powyżej, możesz pominąć wszystkie końcowe opróżnienia.Ta metoda jest prawie sposobem przekazywania opcji do kompilatorów w Makefiles.
I znowu - jeśli dane wejściowe mogą zawierać spacje, robi się brzydki.
źródło