Weiß nicht über , getopt
aber die getopts
builtin kann nur lange Optionen wie das zu handhaben verwendet werden:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
Natürlich funktioniert das so wie es ist nicht, wenn die long-Optionen Argumente haben sollen. Es kann aber gemacht werden, wie ich gelernt habe, daran zu arbeiten. Während ich es anfangs hier aufgenommen habe, wurde mir klar, dass es für Long-Optionen nicht sehr nützlich ist. In diesem Fall verkürzte es meine case
(match)
Felder nur um ein einziges vorhersehbares Zeichen. Was ich jetzt weiß, ist, dass es sich hervorragend für kurze Optionen eignet - es ist am nützlichsten, wenn es eine Zeichenkette unbekannter Länge durchläuft und einzelne Bytes gemäß ihrer Optionszeichenkette auswählt. Aber wenn die Option ist die arg, es gibt wenig , was man mit einer tust for var do case $var in
Kombination , die es tun könnte. Ich denke, es ist besser, es einfach zu halten.
Ich vermute, dasselbe gilt, getopt
aber ich weiß nicht genug darüber, um es mit Sicherheit zu sagen. In Anbetracht der folgenden arg Array, werde ich meine eigene kleine arg Parser zeigen - die in erster Linie auf der evalation / Zuordnung Beziehung hängt Ich bin gekommen , um zu schätzen , alias
und $((shell=math))
.
set -- this is ignored by default --lopt1 -s 'some '\''
args' here --ignored and these are ignored \
--alsoignored andthis --lopt2 'and
some "`more' --lopt1 and just a few more
Das ist die Arg-Saite, mit der ich arbeiten werde. Jetzt:
aopts() { env - sh -s -- "$@"
} <<OPTCASE 3<<\OPTSCRIPT
acase() case "\$a" in $(fmt='
(%s) f=%s; aset "?$(($f)):";;\n'
for a do case "$a" in (--) break;;
(--*[!_[:alnum:]]*) continue;;
(--*) printf "$fmt" "$a" "${a#--}";;
esac;done;printf "$fmt" '--*' ignored)
(*) aset "" "\$a";;esac
shift "$((SHIFT$$))"; f=ignored; exec <&3
OPTCASE
aset() { alias "$f=$(($f${1:-=$(($f))+}1))"
[ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; }
for a do acase; done; alias
#END
OPTSCRIPT
Dabei wird das arg-Array auf zwei verschiedene Arten verarbeitet, je nachdem, ob Sie ein oder zwei durch das --
Trennzeichen getrennte Argumente übergeben . In beiden Fällen gilt dies für Verarbeitungssequenzen für das arg-Array.
Wenn du es so nennst:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Seine erste acase()
Aufgabe wird es sein, seine Funktion so zu schreiben , dass sie so aussieht:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
Und neben shift 3
. Die Befehlsersetzung in der acase()
Funktionsdefinition wird ausgewertet, wenn die aufrufende Shell die Eingaben der Funktion in diesem Dokument erstellt, sie wird jedoch acase()
niemals in der aufrufenden Shell aufgerufen oder definiert. Der Aufruf erfolgt jedoch in der Subshell. Auf diese Weise können Sie die gewünschten Optionen dynamisch in der Befehlszeile angeben.
Wenn Sie ein Array ohne Trennzeichen übergeben, werden nur acase()
Übereinstimmungen für alle Argumente eingetragen, die mit der Zeichenfolge beginnen --
.
Die Funktion führt praktisch die gesamte Verarbeitung in der Subshell aus. Dabei werden die einzelnen Werte des Args iterativ in Aliasnamen gespeichert, denen assoziative Namen zugewiesen sind. Wenn es durch ist, druckt es jeden Wert aus, mit alias
dem es gespeichert hat. Dies ist POSIX-spezifiziert, um alle gespeicherten Werte so zu drucken, dass ihre Werte wieder in die Shell eingegeben werden können. Also, wenn ich es tue ...
aopts --lopt1 --lopt2 -- "$@"
Die Ausgabe sieht folgendermaßen aus:
...ignored...
lopt1='8'
lopt1_1='-s'
lopt1_2='some '\'' args'
lopt1_3='here'
lopt1_4='and'
lopt1_5='just'
lopt1_6='a'
lopt1_7='few'
lopt1_8='more'
lopt2='1'
lopt2_1='and
some "`more'
Beim Durchlaufen der Argumentliste wird nach einer Übereinstimmung mit dem case-Block gesucht. Wenn es dort eine Übereinstimmung findet, wirft es eine Flagge - f=optname
. Bis es wieder eine gültige Option findet, wird jedes nachfolgende Argument zu einem Array hinzugefügt, das es basierend auf dem aktuellen Flag erstellt. Wenn dieselbe Option mehrmals angegeben wird, werden die Ergebnisse zusammengesetzt und nicht überschrieben. Alles, was nicht der Fall ist - oder Argumente, die auf ignorierte Optionen folgen -, werden einem ignorierten Array zugewiesen .
Die Ausgabe wird von der Shell automatisch für die Shell-Eingabe gespeichert.
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
... sollte absolut sicher sein. Wenn es aus irgendeinem Grund nicht sicher ist, sollten Sie wahrscheinlich einen Fehlerbericht bei Ihrem Shell-Betreuer einreichen.
Es werden zwei Arten von Aliaswerten für jede Übereinstimmung zugewiesen. Erstens wird ein Flag gesetzt - dies geschieht unabhängig davon, ob eine Option nicht übereinstimmenden Argumenten vorangeht oder nicht. Jedes Vorkommen von --flag
in der Argumentliste wird also ausgelöst flag=1
. Das verbindet nicht - wird --flag --flag --flag
nur flag=1
. Dieser Wert hat Zuwachs obwohl - für alle Argumente , die ihm folgen könnten. Es kann als Indexschlüssel verwendet werden. Nachdem ich das eval
oben Genannte getan habe, kann ich Folgendes tun:
printf %s\\n "$lopt1" "$lopt2"
...bekommen...
8
1
Und so:
for o in lopt1 lopt2
do list= i=0; echo "$o = $(($o))"
while [ "$((i=$i+1))" -le "$(($o))" ]
do list="$list $o $i \"\${${o}_$i}\" "
done; eval "printf '%s[%02d] = %s\n' $list"; done
AUSGABE
lopt1 = 8
lopt1[01] = -s
lopt1[02] = some ' args
lopt1[03] = here
lopt1[04] = and
lopt1[05] = just
lopt1[06] = a
lopt1[07] = few
lopt1[08] = more
lopt2 = 1
lopt2[01] = and
some "`more
Und zu Argumenten, die nicht passen, würde ich im obigen Feld ignoriert ersetzen for ... in
, um zu bekommen:
ignored = 10
ignored[01] = this
ignored[02] = is
ignored[03] = ignored
ignored[04] = by
ignored[05] = default
ignored[06] = and
ignored[07] = these
ignored[08] = are
ignored[09] = ignored
ignored[10] = andthis
getopts
, aber Sie verwenden den/usr/bin/getopt
Befehl.