Übergabe von Argumenten per Referenz
Möchte ich Fragen, ob es möglich ist, Argumente zu einer script-Funktion per Referenz:
d.h. etwas zu tun, das würde dann so Aussehen in C++:
void boo(int &myint) { myint = 5; }
int main() {
int t = 4;
printf("%d\n", t); //t->4
boo(t);
printf("%d\n", t); //t->5
}
Also dann BASH ich möchte etwas machen wie:
function boo ()
{
var1=$1 # now var1 is global to the script but using it outside
# this function makes me lose encapsulation
local var2=$1 # so i should use a local variable ... but how to pass it back?
var2='new' # only changes the local copy
#$1='new' this is wrong of course ...
# ${!1}='new' # can i somehow use indirect reference?
}
# call boo
SOME_VAR='old'
echo $SOME_VAR # -> old
boo "$SOME_VAR"
echo $SOME_VAR # -> new
Irgendwelche Gedanken würde geschätzt.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist 2018, und dieser Frage verdient ein update. Zumindest in der Bash als Bash-4.3-alpha, können Sie namerefs zu übergeben Sie der Funktion Argumente per Referenz:
Die wichtigen Teile sind hier:
Übergeben den Namen der Variablen, boo, nicht Ihren Wert:
boo SOME_VAR
, nichtboo $SOME_VAR
.Innerhalb der Funktion, mit
local -n ref=$1
zu erklären nameref, um die variable mit dem Namen von$1
, was bedeutet, es ist nicht ein Verweis auf$1
selbst, sondern vielmehr auf eine variable , deren Namen$1
hält, d.h.SOME_VAR
in unserem Fall. Der Wert auf der rechten Seite soll einfach ein string Benennung einer bestehenden Variablen: es ist egal, wie man die Zeichenfolge, so dass Dinge wielocal -n ref="my_var"
oderlocal -n ref=$(get_var_name)
würde auch funktionieren.declare
können auch ersetzenlocal
in Kontexten, die es ermöglichen/erfordern, dass. Sehen Kapitel über die Shell-Parameter in der Bash Reference Manual für weitere Informationen.Der Vorteil dieses Ansatzes ist (wohl) eine bessere Lesbarkeit und, am wichtigsten, zu vermeiden
eval
, deren Sicherheit Fallstricke sind zahlreich und gut dokumentiert.Aus der Bash man-page (Parameter Expansion):
Daher ein Verweis ist der name der Variablen ist. Hier ist ein
swap
Funktion mitvariable Dereferenzierung, die nicht erfordert eine temporäre variable:
Verwenden Sie eine Hilfsfunktion
upvar
:Und es verwenden, wie Sie dies innerhalb
Newfun()
:Für die Rückgabe mehrerer Variablen, verwenden Sie eine andere Hilfsfunktion
upvars
. Dies ermöglicht die übergabe mehrerer Variablen in einem Aufruf, so dass mögliche Konflikte, wenn manupvar
Aufruf ändert eine variable, die in einem anderen nachfolgendenupvar
nennen.Finden Sie unter: http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference für Helfer-Funktion
upvars
und weitere Informationen.Das problem mit:
ist, dass es nicht sicher ist, wenn
$1
geschieht, enthalten einen Befehl:Es wäre besser, verwenden
printf -v
:Aber
printf -v
zuordnen kann-arrays.Darüber hinaus, sowohl
eval
undprintf
wird nicht funktionieren, wenn die variable passiert zu sein, erklärtelocal
:Den Konflikt dort bleibt, auch wenn
local b
istunset
:Habe ich einen Weg gefunden, dies zu tun, aber ich bin nicht sicher, wie richtig das ist:
Damit wir übergeben den Namen der Variablen im Gegensatz zu den Wert-und dann mit eval ...
Bash nicht so etwas wie Referenzen hinein gebaut, so dass im Grunde der einzige Weg, Sie wäre in der Lage zu tun, was Sie wollen, ist das übergeben der Funktion den Namen der globalen Variablen, die Sie wollen, es zu ändern. Und selbst dann müssen Sie eine
eval
Aussage:Ich glaube nicht, dass Sie verwenden können indirekte Verweise hier, weil Bash greift automatisch der Wert der Variablen, deren name gespeichert ist, in der indirekten Referenz. Es nicht geben Ihnen die chance es einzustellen.
Ok, also diese Frage gewartet hat, eine "echte" Lösung für einige Zeit jetzt, und ich bin froh sagen zu können, dass wir nun dies erreichen, ohne die Verwendung von eval überhaupt.
Den Schlüssel zu erinnern ist, deklarieren Sie eine Referenz sowohl der Anrufer wie den angerufenen, zumindest in meinem Beispiel:
Eval sollte niemals verwendet werden, die auf eine Zeichenfolge, die ein Benutzer festlegen kann, weil seine gefährlich. Etwas wie "string; rm -rf ~" schlecht sein. Also in der Regel Ihr bestes, um Lösungen zu finden, wo Sie nicht haben, sich darum zu kümmern.
Jedoch, eval wird benötigt, um die übergebenen Variablen, wie der Kommentar bemerkt.
f() { local x=${!1}; }; f 'a[$(echo hi >&2)]'
. Müssen nur sicherstellen, dass die Eingabe nie so gehandhabt, wie Arithmetik, welche in der Bash kann schwieriger sein, als den meisten Menschen bewusst ist.Ausgabe:
Struktur für den Aufruf der Funktion ist:
Name der Variablen übergeben wird, fuction über HAUSTIERE und SEP während der string-append übergeben der üblichen Weise als Wert. "${!1}" bezieht sich auf Inhalte von globalen HAUSTIERE variable. Am Anfang ist die variable leer und Inhalte, Hinzugefügt wird, jedes mal, wenn wir die Funktion aufrufen. Trennzeichen kann beliebig gewählt werden. "eval" Start-Linien-update HAUSTIERE variable.
Dies ist, was funktioniert für mich, auf Ubuntu bash-shell