Wie verwende ich getopt in der Bash-Befehlszeile mit nur langen Optionen?

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 und getopt infizieren Ihre Antwort? Sie beginnen mit dem Kommentieren von getopts und erwähnen dann nur getopt.
  • @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 Aufschrift getopts korrigiert. Vielen Dank. getopts ' führt nicht einmal lange Optionen aus, sodass dies für getopts 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 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.