In der Bash-Befehlszeile befindet sich ein getopt
-Befehl. getopt
kann mit kurzen Optionen (wie getopt -o axby "$@"
) und sowohl mit kurzen als auch mit langen Optionen (wie getopt -o axby -l long-key -- "$@"
), aber jetzt benötige ich nur lange Optionen (dh kurze Optionen existieren überhaupt nicht), jedoch den Befehl getopt -l long-key -- "$@"
analysiert die Option --long-key
nicht korrekt. Wie kann ich den Befehl getopt
mit nur langen Optionen verwenden? Oder ist es unmöglich oder ist es nur ein Fehler des Befehls getopt
?
Kommentare
- Sie Tag für den internen
getopts
, aber Sie verwenden den Befehl/usr/bin/getopt
. - @Anthon Entschuldigung, ich habe verwendet das falsche Tag, aber ich habe ' nicht genug Reputation, um ein weiteres Tag hinzuzufügen, das 300 Reputationen benötigt. Ich habe jedoch gerade das falsche Tag gelöscht.
Antwort
getopt
ist vollkommen in Ordnung, da es keine kurzen Optionen gibt. Aber Sie müssen sagen, dass Sie keine kurzen Optionen haben. Es ist eine Eigenart in der Syntax – aus dem Handbuch:
Wenn nein
-o
oder--options
befindet sich im ersten Teil. Der erste Parameter des zweiten Teils wird als kurze Optionszeichenfolge verwendet.
Das passiert in Ihrem Test: getopt -l long-key -- --long-key foo
behandelt --long-key
als Liste der Optionen -egklnoy
und foo
als einziges Argument. Verwenden Sie
getopt -o "" -l long-key -- "$@"
zB
$ getopt -l long-key -o "" -- --long-key foo --long-key -- "foo" $ getopt -l long-key -o "" -- --long-key --not-recognized -n foo getopt: unrecognized option "--not-recognized" getopt: invalid option -- "n" --long-key -- "foo"
Kommentare
- Hat das OP ' das Mischen von
getopts
undgetopt
infizieren Ihre Antwort? Sie beginnen mit dem Kommentieren vongetopts
und erwähnen dann nurgetopt
. - @Anthon Meine ganze Antwort bezieht sich auf das Programm
getopt
von GNU coreutils, worum es bei der Frage geht. I haben den Text mit der Aufschriftgetopts
korrigiert. Vielen Dank.getopts
' führt nicht einmal lange Optionen aus, sodass dies fürgetopts
nicht zutreffen würde - Das OP hatte ursprünglich das Tag
getopts
. Ich wollte deine Antwort nicht ändern, weil du normalerweise viel besser weißt als ich, worüber du schreibst 🙂 - Ich habe fast eine Stunde verloren, um das herauszufinden. Du hast mir nur ein paar vergebliche Schlucke Kaffee gespart. Danke … lassen Sie uns diesen Kaffee jetzt besser nutzen. ☕️
Antwort
Keine Ahnung über getopt
, aber die getopts
integriert kann verwendet werden, um nur lange Optionen wie diese zu verarbeiten:
while getopts :-: o do case "$o$OPTARG" in (-longopt1) process ;; (-longopt2) process ;; esac; done
Natürlich ist das nicht so. “ Es funktioniert nicht, wenn die Long-Optionen Argumente haben sollen. Es kann zwar gemacht werden, aber wie ich gelernt habe, daran zu arbeiten. Während ich es anfangs hier aufgenommen habe, habe ich festgestellt, dass es für Long-Optionen nicht viel Nutzen hat. In diesem Fall hat es nur meine case
(match)
Felder durch ein einzelnes, vorhersagbares Zeichen. Was ich jetzt weiß, ist, dass es sich hervorragend für kurze Optionen eignet – es ist am nützlichsten, wenn es eine Zeichenfolge unbekannter Länge durchläuft und einzelne Bytes gemäß ihrer Optionszeichenfolge auswählt Aber wenn die Option das Argument ist, gibt es nicht viel, was Sie mit einer for var do case $var in
-Kombination tun, die es tun könnte. Es ist besser, Ich denke, um es einfach zu halten.
Ich vermute, dass dies auch für getopt
gilt, aber ich weiß nicht genug darüber, um es mit Sicherheit zu sagen. In Anbetracht des folgenden Arg-Arrays werde ich meinen eigenen kleinen Arg-Parser demonstrieren – was hauptsächlich von der Beziehung zwischen Bewertung und Zuweisung abhängt, die ich für alias
und .
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 Argumentzeichenfolge, 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
Damit wird das arg-Array auf zwei verschiedene Arten verarbeitet, je nachdem, ob Sie ihm ein oder zwei Sätze von Argumenten übergeben, die durch das Trennzeichen --
getrennt sind. In beiden Fällen gilt dies für Verarbeitungssequenzen für das arg-Array.
Wenn Sie es wie folgt aufrufen:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Die erste Reihenfolge von Das Geschäft besteht darin, die Funktion acase()
so zu schreiben, dass sie wie folgt 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 Befehlssubstitution in der Funktionsdefinition acase()
wird ausgewertet, wenn die aufrufende Shell die Eingabedokumente der Funktion erstellt, acase()
jedoch Wird in der aufrufenden Shell nie aufgerufen oder definiert. Es wird jedoch natürlich in der Subshell aufgerufen. Auf diese Weise können Sie die gewünschten Optionen dynamisch in der Befehlszeile angeben.
Wenn Sie eine übergeben Unbegrenztes Array Es füllt einfach acase()
mit Übereinstimmungen für alle Argumente, die mit der Zeichenfolge --
beginnen.
Die Funktion führt praktisch die gesamte Verarbeitung in der Unterschale durch – iterativ werden alle Werte des Args in Aliasnamen gespeichert, denen assoziative Namen zugewiesen sind. Wenn es fertig ist, druckt es jeden Wert aus, den es mit alias
gespeichert hat. Dies ist POSIX-spezifiziert, um alle gespeicherten Werte so zu drucken, dass ihre Werte wieder in die Shell eingegeben werden können. Wenn ich also …
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 Arg-Liste wird anhand des Fallblocks nach einer Übereinstimmung gesucht. Wenn es dort eine Übereinstimmung findet, wirft es ein Flag – f=optname
. Bis es wieder eine gültige Option findet, fügt es jedes nachfolgende Argument einem Array hinzu, das es basierend auf dem aktuellen Flag erstellt. Wenn dieselbe Option mehrmals angegeben wird, werden die Ergebnisse zusammengesetzt und nicht überschrieben. Alles, was nicht für den Fall ist – oder Argumente, die ignorierten Optionen folgen -, werden einem ignorierten Array zugewiesen.
Die Ausgabe wird für die Shell-Eingabe automatisch von der Shell gesichert, und so weiter :
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. Zunächst wird ein Flag gesetzt. Dies geschieht unabhängig davon, ob eine Option vor nicht übereinstimmenden Argumenten steht oder nicht. Jedes Auftreten von --flag
in der Arg-Liste löst also flag=1
aus. Dies setzt sich nicht zusammen – --flag --flag --flag
erhält nur flag=1
. Dieser Wert erhöht jedoch – für alle Argumente, die darauf folgen könnten. Es kann als Indexschlüssel verwendet werden. Nachdem ich das eval
oben ausgeführt habe, kann ich Folgendes tun:
printf %s\\n "$lopt1" "$lopt2"
… um …
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 für Argumente, die nicht übereinstimmten, würde ich ignoriert im obigen Feld for ... in
einsetzen, um Folgendes zu erhalten:
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