Ich erinnere mich, dass ich irgendwo ein bash
Skript gesehen habe, das die Liste der Positionsparameter, Analyseflags und Optionen mit Argumenten verwendet case
und shift
durchgeht, wenn es auf sie trifft, und sie nach dem Parsen entfernt, um nur die bloßen Argumente zu belassen, die später vom Rest der verarbeitet werden Skript.
Wenn Sie beispielsweise die Befehlszeile von analysieren cp -R file1 -t /mybackup file2 -f
, werden zunächst die Parameter durchlaufen, erkannt, dass der Benutzer angefordert hat, in Verzeichnisse von abzusteigen -R
, das Ziel von anzugeben -t /mybackup
und das Kopieren von zu erzwingen -f
, und diese aus der Liste der Parameter entfernt das Programm, das file1 file2
als verbleibende Argumente verarbeitet werden soll.
Aber ich scheine nicht in der Lage zu sein, mich an das Skript zu erinnern, das ich wann immer gesehen habe. Ich möchte das nur können. Ich habe auf verschiedenen Websites gegoogelt und eine Liste der relevanten Seiten angehängt, die ich untersucht habe.
Eine Frage auf dieser Website, die speziell nach "auftragsunabhängigen Optionen" gestellt wurde, aber sowohl die Einzelantwort als auch die Antwort auf die Frage, auf die sie gestellt wurde, berücksichtigt keine Fälle wie die oben genannten, in denen die Optionen mit normalen Argumenten gemischt sind, von denen ich annehme, dass dies die war Grund für die Person, auftragsunabhängige Optionen ausdrücklich zu erwähnen .
Da bash
das eingebaute getopts
Argument beim ersten Argument ohne Option zu enden scheint, scheint es als Lösung nicht ausreichend zu sein. Aus diesem Grund wird auf der Wooledge BashFAQ-Seite (siehe unten) erläutert, wie die Argumente neu angeordnet werden. Ich möchte jedoch vermeiden, mehrere Arrays zu erstellen, falls die Argumentliste ziemlich lang ist.
Da shift
es nicht unterstützt wird, einzelne Argumente aus der Mitte der Parameterliste zu entfernen, bin ich mir nicht sicher, wie ich das, was ich frage, auf einfache Weise implementieren kann.
Ich würde gerne hören, ob jemand Lösungen zum Entfernen von Argumenten aus der Mitte der Parameterliste hat, ohne ein ganz neues Array zu erstellen.
Seiten, die ich bereits gesehen habe:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- Verwenden von getopts im Bash-Shell-Skript, um lange und kurze Befehlszeilenoptionen abzurufen
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- Bash-Argument Fall für Argumente in $ @
- Was ist der kanonische Weg, um auftragsunabhängige Optionen in Bash-Skripten zu implementieren?
- Wie gehe ich mit Schaltern in einem Shell-Skript um?
Antworten:
POSIXly sollte das Parsen nach Optionen am
--
oder beim ersten Argument ohne Option (oder ohne Option) beginnen, je nachdem, was zuerst eintritt. Also reindass die an
file1
, socp
rekursiv alle kopieren sollfile1
,-t
,/mybackup
undfile2
in das-f
Verzeichnis.GNU
getopt(3)
(das GNUcp
zum Parsen von Optionen verwendet (und hier verwenden Sie GNU,cp
da Sie die GNU-spezifische-t
Option verwenden))$POSIXLY_CORRECT
akzeptiert Optionen nach Argumenten , sofern die Umgebungsvariable nicht festgelegt ist. Es entspricht also tatsächlich dem Parsing von POSIX-Optionsstilen:Die
getopts
in die GNU-Shell (bash
) integrierte Shell verarbeitet nur den POSIX-Stil. Es werden auch keine langen Optionen oder Optionen mit optionalen Argumenten unterstützt.Wenn Sie die Optionen auf die gleiche Weise wie GNU analysieren möchten
cp
, müssen Sie die GNU-getopt(3)
API verwenden. Unter Linux können Sie dafür das erweitertegetopt
Dienstprogramm von verwendenutil-linux
( diese erweiterte Version desgetopt
Befehls wurde auch auf einige andere Unices wie FreeBSD portiert ).Das
getopt
wird die Optionen in kanonischer Weise neu anordnen , die Sie es einfach mit einer analysieren erlaubtwhile/case
Schleife.Sie würden es normalerweise verwenden als:
Beachten Sie auch, dass dadurch
getopt
Optionen genauso analysiert werden wie bei GNUcp
. Insbesondere unterstützt es die langen Optionen (und gibt sie abgekürzt ein) und berücksichtigt die$POSIXLY_CORRECT
Umgebungsvariablen (die beim Festlegen die Unterstützung für Optionen nach Argumenten deaktivieren) auf die gleiche Weise wie GNUcp
.Beachten Sie, dass die Verwendung von gdb und das Drucken der
getopt_long()
empfangenen Argumente beim Erstellen der folgenden Parameter hilfreich sein kanngetopt(1)
:Dann können Sie verwenden
getopt
als:Denken Sie daran, dass sich
cp
die Liste der unterstützten Optionen von GNU von einer Version zur nächsten ändern kann undgetopt
nicht überprüft werden kann, ob Sie--sparse
beispielsweise der Option einen legalen Wert übergeben .quelle
while [ "$#" -gt 0 ]
io nur verwendenwhile (($#))
? Ist es nur, um einen Bashismus zu vermeiden?(($#))
ist eher ein Kshismus .Jedes Mal
getopts
, wenn ein Argument verarbeitet wird, wird nicht erwartet, dass die Shell-Variable$OPTIND
auf die nächste Zahl in der Argumentliste gesetzt wird, die verarbeitet werden soll, und es wird eine andere als 0 zurückgegeben. Wenn der$OPTIND
Wert 1 festgelegt ist,getopts
wird POSIX angegeben, um a zu akzeptieren neue Argumentliste. Dies überwacht also nur diegetopts
Rückkehr, speichert Inkremente eines Zählers plus$OPTIND
für jede fehlgeschlagene Rückgabe, verschiebt die fehlgeschlagenen Argumente und setzt$OPTIND
jeden fehlgeschlagenen Versuch zurück. Sie können es wieopts "$@"
folgt verwenden - obwohl Sie diecase
Schleife anpassen oder in einer Variablen speichern und diesen Abschnitt in ändern möchteneval $case
.Während der Ausführung wird
$args
auf jedes Argument gesetzt, dasgetopts
nicht behandelt wurde ... also ...AUSGABE
Dies funktioniert in
bash
,dash
,zsh
,ksh93
,mksh
... na ja, ich beenden an dieser Stelle versuchen. In jeder Schale bekam es auch$[Rtf]flag
und$targ
. Der Punkt ist, dass alle Zahlen für die Argumente,getopts
die nicht verarbeitet werden wollten, erhalten blieben.Das Ändern des Optionsstils machte ebenfalls keinen Unterschied. Es hat funktioniert wie
-Rf -t/mybackup
oder-R -f -t /mybackup
. Es funktionierte in der Mitte der Liste, am Ende der Liste oder am Anfang der Liste ...Der beste Weg ist jedoch, ein
--
Ende der Optionen in Ihre Arg-Liste aufzunehmen und diesshift "$(($OPTIND-1))"
am Ende einesgetopts
Verarbeitungslaufs zu tun . Auf diese Weise entfernen Sie alle verarbeiteten Parameter und behalten das Ende der Argumentliste bei.Eine Sache, die ich gerne mache, ist, lange Optionen in kurze zu übersetzen - und das mache ich auf sehr ähnliche Weise, weshalb diese Antwort leicht kam - bevor ich renne
getopts
.quelle
cp -t --file foo
odercp -- --file foo
) konvertieren und würde nicht mit abgekürzten (--fi
...) eingegebenen Optionen oder mit der--target=/dest
Syntax fertig werden .getopts
Ding durch eine viel einfachere Funktion ersetzt.opts()
einen Einfluss auf Ihre eigene Antwort hat, da esopts()
in einer einzigen Schleife arbeitet - jedes Argument nur einmal berührt - und dies zuverlässig (soweit ich das beurteilen kann) , portabel und ohne eine einzige Unterschale.-R
,-t /mybackup
,-f
). Ich werde meine Abstimmung vorerst$a
beibehalten, da sie immer noch verschleiert ist, Sie nicht initialisiert verwenden undargs= opts...
wahrscheinlichargs
nach deropts
Rückkehr in vielen Shells (einschließlich Bash) nicht gesetzt (oder auf den vorherigen Wert gesetzt) bleiben.bash
- ich hasse das. Wenn die Funktion eine aktuelle Shell- Funktion ist, sollte sie meiner Meinung nach beibehalten werden. Ich Adressierung diese Dinge - wie die aktuelle Funktion, mit mehr Tests, robust gemacht werden könnte , alle Fälle zu handhaben , und sogar Flag Argument mit seiner vorhergehenden Option, aber ich stimme nicht , dass es verschleiert . Wie geschrieben, ist es das einfachste und direkteste Mittel, um seine Aufgabe zu erfüllen, das ich mir vorstellen kann.test
Dannshift
macht es wenig Sinn, wenn Sie es in jedem fehlgeschlagenenshift
Fall tun solltenreturn
. Es ist nicht beabsichtigt, etwas anderes zu tun.