Eine andere Lösung ohne getopt [s], POSIX, alter Unix-Stil
Ähnlich wie bei der Lösung, die Bruno Bronosky hier gepostet hat, handelt es sich um eine Lösung ohne Verwendung vongetopt(s)
.
Das Hauptunterscheidungsmerkmal meiner Lösung besteht darin, dass Optionen miteinander verkettet werden können, genau wie dies tar -xzf foo.tar.gz
gleich ist tar -x -z -f foo.tar.gz
. Und genau wie in tar
,ps
usw. der führenden Bindestrich ist optional für einen Block von Short - Optionen (aber dies kann leicht geändert werden). Es werden auch lange Optionen unterstützt (aber wenn ein Block mit einem beginnt, sind zwei führende Bindestriche erforderlich).
Code mit Beispieloptionen
#!/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
Die Beispielverwendung finden Sie in den Beispielen weiter unten.
Position von Optionen mit Argumenten
Für was es dort wert ist, sind die Optionen mit Argumenten nicht die letzten (nur lange Optionen müssen sein). Während z. B. in tar
(zumindest in einigen Implementierungen) die f
Optionen zuletzt sein müssen, da der Dateiname folgt ( tar xzf bar.tar.gz
funktioniert, tar xfz bar.tar.gz
aber nicht funktioniert), ist dies hier nicht der Fall (siehe die späteren Beispiele).
Mehrere Optionen mit Argumenten
Als weiteren Bonus werden die Optionsparameter in der Reihenfolge der Optionen von den Parametern mit den erforderlichen Optionen verbraucht. Schauen Sie sich hier die Ausgabe meines Skripts mit der Befehlszeile abc X Y Z
(oder -abc X Y Z
) an:
Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!
Auch lange Optionen verkettet
Sie können auch lange Optionen im Optionsblock haben, da diese zuletzt im Block vorkommen. Die folgenden Befehlszeilen sind also alle gleichwertig (einschließlich der Reihenfolge, in der die Optionen und ihre Argumente verarbeitet werden):
-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
All dies führt zu:
Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...
Nicht in dieser Lösung
Optionale Argumente
Optionen mit optionalen Argumenten sollten mit ein wenig Arbeit möglich sein, z. B. indem Sie nach vorne schauen, ob es einen Block ohne Bindestrich gibt. Der Benutzer müsste dann vor jedem Block nach einem Block mit einem Parameter mit einem optionalen Parameter einen Bindestrich setzen. Möglicherweise ist dies zu kompliziert, um mit dem Benutzer zu kommunizieren, sodass in diesem Fall besser nur ein führender Bindestrich erforderlich ist.
Mit mehreren möglichen Parametern wird es noch komplizierter. Ich würde davon abraten, die Optionen so zu gestalten, dass sie klug sind, indem ich feststelle, ob ein Argument dafür geeignet ist oder nicht (z. B. wenn eine Option nur eine Zahl als optionales Argument verwendet), da dies in Zukunft möglicherweise nicht mehr funktioniert.
Ich persönlich bevorzuge zusätzliche Optionen anstelle optionaler Argumente.
Optionsargumente mit Gleichheitszeichen
Genau wie bei optionalen Argumenten bin ich kein Fan davon (Übrigens, gibt es einen Thread, in dem die Vor- und Nachteile verschiedener Parameterstile diskutiert werden?), Aber wenn Sie dies möchten, können Sie es wahrscheinlich selbst implementieren, wie unter http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop mit einer --long-with-arg=?*
case-Anweisung und anschließendem Entfernen des Gleichheitszeichens (dies ist übrigens die Site, die besagt, dass die Verkettung von Parametern mit einigem Aufwand möglich ist, aber [es] als Übung für den Leser hinterlassen hat "was mich dazu brachte, sie beim Wort zu nehmen, aber ich fing von vorne an).
Weitere Hinweise
POSIX-konform, funktioniert auch auf alten Busybox - Setups ich zu tun hatte (mit zB cut
, head
und getopts
fehlt).
zparseopts -D -E -M -- d=debug -debug=d
Und beide-d
und--debug
im$debug
Arrayecho $+debug[1]
geben 0 oder 1 zurück, wenn eine davon verwendet wird. Ref: zsh.org/mla/users/2011/msg00350.html