Wie kann ich ein Array als Parameter an eine Bash-Funktion übergeben?
Hinweis: Nachdem ich hier auf Stack Overflow keine Antwort gefunden habe, habe ich meine etwas grobe Lösung selbst veröffentlicht. Es kann nur ein Array übergeben werden, und es ist das letzte Element der Parameterliste. Eigentlich übergibt es das Array überhaupt nicht, sondern eine Liste seiner Elemente, die durch call_function () zu einem Array zusammengesetzt werden, aber es hat bei mir funktioniert. Wenn jemand einen besseren Weg kennt, können Sie ihn hier hinzufügen.
Antworten:
Sie können mehrere Arrays als Argumente übergeben, indem Sie Folgendes verwenden:
wird widerhallen:
Bearbeiten / Notizen: (aus Kommentaren unten)
descTable
undoptsTable
werden als Namen übergeben und in der Funktion erweitert. Daher$
wird bei der Angabe als Parameter kein Wert benötigt.descTable
etc definiert istlocal
, da die Einheimischen für die von ihnen aufgerufenen Funktionen sichtbar sind.!
in${!1}
erweitert die Variable arg 1.declare -a
macht das indizierte Array nur explizit, es ist nicht unbedingt notwendig.quelle
Hinweis: Dies ist die etwas grobe Lösung, die ich selbst veröffentlicht habe, nachdem ich hier auf Stack Overflow keine Antwort gefunden habe. Es kann nur ein Array übergeben werden, und es ist das letzte Element der Parameterliste. Eigentlich übergibt es das Array überhaupt nicht, sondern eine Liste seiner Elemente, die durch call_function () zu einem Array zusammengesetzt werden, aber es hat bei mir funktioniert. Etwas später veröffentlichte Ken seine Lösung, aber ich habe meine hier als "historische" Referenz aufbewahrt.
Verbessert von TheBonsai, danke.
quelle
called_function "${#array[@]}" "${array[@]}" "${#array2[@]}" "${array2[@]}"
etc ... immer noch mit einigen offensichtlichen Einschränkungen, aber wirklich besser, um das Problem auf eine Weise zu lösen, die die Sprache unterstützt, als zu versuchen, die Sprache so zu biegen, wie Sie es in anderen Sprachen gewohnt sind.Kommentar zur Ken Bertelson-Lösung und Beantwortung von Jan Hettich:
Wie es funktioniert
Die
takes_ary_as_arg descTable[@] optsTable[@]
Line-In-try_with_local_arys()
Funktion sendet:descTable
undoptsTable
Arrays , die auf die zugegriffen werden kanntakes_ary_as_arg
Funktion.takes_ary_as_arg()
Funktion empfängtdescTable[@]
undoptsTable[@]
als Zeichenfolgen, das heißt$1 == descTable[@]
und$2 == optsTable[@]
.Zu Beginn der
takes_ary_as_arg()
Funktion wird die${!parameter}
Syntax verwendet, die als indirekte Referenz oder manchmal als doppelte Referenz bezeichnet wird. Dies bedeutet, dass anstelle des$1
Werts von 'der Wert des erweiterten Werts von$1
beispielsweise verwendet wird:ebenfalls für
$2
.argAry1=("${!1}")
einfügen, wird esargAry1
als Array (die folgenden Klammern=
) mit dem erweiterten erstelltdescTable[@]
, genau wie wenn SieargAry1=("${descTable[@]}")
direkt dort schreiben . dasdeclare
gibt es nicht.NB: Es ist erwähnenswert, dass die Array-Initialisierung mit diesem Klammerformular das neue Array gemäß dem
IFS
oder internen Feldtrennzeichen initialisiert, das standardmäßig Registerkarte , Zeilenumbruch und Leerzeichen ist . in diesem Fall wird, da es die[@]
Notation verwendet, jedes Element für sich gesehen, als ob es zitiert worden wäre (im Gegensatz zu[*]
).Meine Reservierung damit
Der
BASH
lokale Variablenbereich ist die aktuelle Funktion und jede von ihr aufgerufene untergeordnete Funktion. Dies bedeutet, dass dietakes_ary_as_arg()
Funktion diesedescTable[@]
undoptsTable[@]
Arrays "sieht" und somit funktioniert (siehe obige Erklärung).Schauen Sie sich in diesem Fall diese Variablen direkt an. Es ist wie dort zu schreiben:
Siehe obige Erklärung, in der nur
descTable[@]
die Werte des Arrays entsprechend dem aktuellen Wert kopiert werdenIFS
.Zusammenfassend
Ich möchte auch den obigen Kommentar von Dennis Williamson hervorheben: Spärliche Arrays (Arrays ohne alle definierten Schlüssel - mit "Löchern" darin) funktionieren nicht wie erwartet - wir würden die Schlüssel verlieren und das Array "verdichten".
Davon abgesehen sehe ich den Wert für die Verallgemeinerung, Funktionen können also die Arrays (oder Kopien) erhalten, ohne die Namen zu kennen:
für echte Kopien: Wir können eine Auswertung für die Schlüssel verwenden, zum Beispiel:
und dann eine Schleife, mit der eine Kopie erstellt wird. Hinweis: Hier
!
wird nicht die vorherige indirekte / doppelte Auswertung verwendet, sondern im Array-Kontext werden die Array-Indizes (Schlüssel) zurückgegeben.descTable
undoptsTable
Zeichenfolgen (ohne[@]
) übergeben würden, könnten wir das Array selbst (wie in der Referenz) mit verwendeneval
. für eine generische Funktion, die Arrays akzeptiert.quelle
Array1
, dannArray2
wird es praktisch, die Array-Namen zu übergeben.Das Grundproblem hierbei ist, dass die Bash-Entwickler, die Arrays entworfen / implementiert haben, das Hündchen wirklich durcheinander gebracht haben. Sie entschieden, dass dies
${array}
nur eine kurze Hand war${array[0]}
, was ein schlimmer Fehler war. Besonders wenn Sie bedenken, dass dies${array[0]}
keine Bedeutung hat und als leere Zeichenfolge ausgewertet wird, wenn der Array-Typ assoziativ ist.Das Zuweisen eines Arrays erfolgt in der Form,
array=(value1 ... valueN)
in der value die Syntax hat[subscript]=string
, wodurch ein Wert direkt einem bestimmten Index im Array zugewiesen wird. Dies macht es so, dass es zwei Arten von Arrays geben kann, numerisch indiziert und Hash-indiziert (im Bash-Sprachgebrauch assoziative Arrays genannt). Es macht es auch so, dass Sie spärliche numerisch indizierte Arrays erstellen können. Das Weglassen des[subscript]=
Teils ist eine kurze Hand für ein numerisch indiziertes Array, beginnend mit dem Ordnungsindex 0 und inkrementierend mit jedem neuen Wert in der Zuweisungsanweisung.Daher
${array}
sollte auf das gesamte Array, Indizes und alle ausgewertet werden . Es sollte umgekehrt zur Zuweisungsanweisung ausgewertet werden. Jeder CS-Major im dritten Jahr sollte das wissen. In diesem Fall würde dieser Code genau so funktionieren, wie Sie es erwarten würden:Dann würde das Übergeben von Arrays nach Wert an Funktionen und das Zuweisen eines Arrays zu einem anderen funktionieren, wie es der Rest der Shell-Syntax vorschreibt. Da sie dies jedoch nicht richtig gemacht haben,
=
funktioniert der Zuweisungsoperator nicht für Arrays, und Arrays können nicht als Wert an Funktionen oder Subshells übergeben oder allgemein ausgegeben werden (echo ${array}
), ohne dass Code zum Durchkauen verwendet wird .Wenn es also richtig gemacht worden wäre, würde das folgende Beispiel zeigen, wie die Nützlichkeit von Arrays in Bash wesentlich besser sein könnte:
Die resultierende Ausgabe sollte sein:
Dann könnten Arrays den Zuweisungsoperator verwenden und als Wert an Funktionen und sogar andere Shell-Skripte übergeben werden. Einfach durch Ausgabe in eine Datei zu speichern und einfach aus einer Datei in ein Skript zu laden.
Leider wurden wir von einem Bash-Entwicklungsteam der Superlative enttäuscht.
Um ein Array an eine Funktion zu übergeben, gibt es wirklich nur eine Option, nämlich die Verwendung der Funktion nameref:
führt zu folgender Ausgabe:
Da dies als Referenz übergeben wird, können Sie dem Array in der Funktion auch zuweisen. Ja, das Array, auf das verwiesen wird, muss einen globalen Bereich haben, aber das sollte keine allzu große Sache sein, wenn man bedenkt, dass es sich um Shell-Scripting handelt. Um ein assoziatives oder dünn indiziertes Array nach Wert an eine Funktion zu übergeben, müssen alle Indizes und Werte als einzelne Zeichenfolgen wie folgt in die Argumentliste geworfen werden (nicht allzu nützlich, wenn es sich um ein großes Array handelt):
und dann eine Reihe von Code in die Funktion schreiben, um das Array wieder zusammenzusetzen.
quelle
local -n
ist besser und aktueller als die akzeptierte Antwort. Diese Lösung funktioniert auch für eine Variable eines beliebigen Typs. Das in dieser Antwort aufgeführte Beispiel kann auf verkürzt werdenlocal -n ARR=${1}
. Die-n
Option fürlocal
/declare
ist jedoch nur in Bash Version 4.3 und höher verfügbar.funky ARR
), gibt die Shell eine Warnung auscircular name reference
, da die Funktion im Grunde versucht, dies zu tunlocal -n ARR=ARR
. Gute Diskussion zu diesem Thema.Die Antwort von DevSolar hat einen Punkt, den ich nicht verstehe (vielleicht hat er einen bestimmten Grund dafür, aber mir fällt keiner ein): Er setzt das Array aus den Positionsparametern Element für Element iterativ.
Ein einfacher Ansatz wäre
quelle
Beispiel
quelle
Eine einfache Möglichkeit, mehrere Arrays als Parameter zu übergeben, besteht darin, eine durch Zeichen getrennte Zeichenfolge zu verwenden. Sie können Ihr Skript folgendermaßen aufrufen:
Dann können Sie es wie folgt in Ihren Code extrahieren:
Auf diese Weise können Sie tatsächlich mehrere Arrays als Parameter übergeben, und es müssen nicht die letzten Parameter sein.
quelle
Dieser funktioniert auch mit Leerzeichen:
quelle
Mit ein paar Tricks können Sie benannte Parameter zusammen mit Arrays an Funktionen übergeben.
Mit der von mir entwickelten Methode können Sie auf Parameter zugreifen, die an eine Funktion wie die folgende übergeben wurden:
Mit anderen Worten, Sie können Ihre Parameter nicht nur bei ihren Namen aufrufen (was einen besser lesbaren Kern ausmacht), sondern auch Arrays übergeben (und Verweise auf Variablen - diese Funktion funktioniert jedoch nur in Bash 4.3)! Außerdem befinden sich die zugeordneten Variablen alle im lokalen Bereich, genau wie $ 1 (und andere).
Der Code, mit dem dies funktioniert, ist ziemlich leicht und funktioniert sowohl in Bash 3 als auch in Bash 4 (dies sind die einzigen Versionen, mit denen ich es getestet habe). Wenn Sie an weiteren Tricks wie diesen interessiert sind, die das Entwickeln mit Bash viel schöner und einfacher machen, können Sie sich mein Bash Infinity Framework ansehen. Der folgende Code wurde für diesen Zweck entwickelt.
quelle
Nur um die akzeptierte Antwort zu ergänzen, da ich festgestellt habe, dass es nicht gut funktioniert, wenn der Array-Inhalt wie folgt aussieht:
In diesem Fall wird jedes Mitglied des Arrays aufgeteilt, sodass das Array, das die Funktion sieht, entspricht:
Um diesen Fall zum Laufen zu bringen, habe ich den Variablennamen an die Funktion übergeben und dann eval verwendet:
Nur meine 2 ©
quelle
So hässlich es auch ist, hier ist eine Problemumgehung, die funktioniert, solange Sie kein Array explizit übergeben, sondern eine Variable, die einem Array entspricht:
Ich bin sicher, dass jemand eine klarere Implementierung der Idee finden kann, aber ich habe festgestellt, dass dies eine bessere Lösung ist, als ein Array als zu übergeben
"{array[@]"}
und dann intern mit darauf zuzugreifenarray_inside=("$@")
. Dies wird kompliziert, wenn andere Positions- /getopts
Parameter vorhanden sind. In diesen Fällen musste ich zuerst die Parameter bestimmen und dann entfernen, die nicht mit dem Array verknüpft sind, indem ich eine Kombination ausshift
und Entfernen von Array-Elementen verwendete.Eine puristische Perspektive betrachtet diesen Ansatz wahrscheinlich als eine Verletzung der Sprache, aber pragmatisch gesehen hat mir dieser Ansatz viel Kummer erspart. Zu einem verwandten Thema verwende ich auch
eval
, um einer Variablen, die nach einem Parameter benannt ist, dentarget_varname
ich an die Funktion übergebe , ein intern erstelltes Array zuzuweisen :eval $target_varname=$"(${array_inside[@]})"
Hoffe das hilft jemandem.
quelle
Voraussetzung : Funktion zum Suchen einer Zeichenfolge in einem Array.
Dies ist eine leichte Vereinfachung der DevSolar-Lösung, da die übergebenen Argumente verwendet werden, anstatt sie zu kopieren.
quelle
Meine kurze Antwort lautet:
${test_array[*]}
und${test_array2[*]}
von "" umgeben sein sollte, sonst scheitern Sie.quelle