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ówne tar -x -z -f foo.tar.gz
. I podobnie jak w tar
, 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
#!/bin/sh
echo
echo "POSIX-compliant getopt(s)-free old-style-supporting option parser from phk@[se.unix]"
echo
print_usage() {
echo "Usage:
$0 {a|b|c} [ARG...]
Options:
--aaa-0-args
-a
Option without arguments.
--bbb-1-args ARG
-b ARG
Option with one argument.
--ccc-2-args ARG1 ARG2
-c ARG1 ARG2
Option with two arguments.
" >&2
}
if [ $# -le 0 ]; then
print_usage
exit 1
fi
opt=
while :; do
if [ $# -le 0 ]; then
# no parameters remaining -> end option parsing
break
elif [ ! "$opt" ]; then
# we are at the beginning of a fresh block
# remove optional leading hyphen and strip trailing whitespaces
opt=$(echo "$1" | sed 's/^-\?\([a-zA-Z0-9\?-]*\)/\1/')
fi
# get the first character -> check whether long option
first_chr=$(echo "$opt" | awk '{print substr($1, 1, 1)}')
[ "$first_chr" = - ] && long_option=T || long_option=F
# note to write the options here with a leading hyphen less
# also do not forget to end short options with a star
case $opt in
-)
# end of options
shift
break
;;
a*|-aaa-0-args)
echo "Option AAA activated!"
;;
b*|-bbb-1-args)
if [ "$2" ]; then
echo "Option BBB with argument '$2' activated!"
shift
else
echo "BBB parameters incomplete!" >&2
print_usage
exit 1
fi
;;
c*|-ccc-2-args)
if [ "$2" ] && [ "$3" ]; then
echo "Option CCC with arguments '$2' and '$3' activated!"
shift 2
else
echo "CCC parameters incomplete!" >&2
print_usage
exit 1
fi
;;
h*|\?*|-help)
print_usage
exit 0
;;
*)
if [ "$long_option" = T ]; then
opt=$(echo "$opt" | awk '{print substr($1, 2)}')
else
opt=$first_chr
fi
printf 'Error: Unknown option: "%s"\n' "$opt" >&2
print_usage
exit 1
;;
esac
if [ "$long_option" = T ]; then
# if we had a long option then we are going to get a new block next
shift
opt=
else
# if we had a short option then just move to the next character
opt=$(echo "$opt" | awk '{print substr($1, 2)}')
# if block is now empty then shift to the next one
[ "$opt" ] || shift
fi
done
echo "Doing something..."
exit 0
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, ale tar 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
):
Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!
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:
Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...
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
i getopts
brakuje).
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.html