Ich schreibe eine Reihe von Shell-Funktionen, die sowohl in Bash als auch in KornShell93 funktionieren sollen, aber bei Bash stoße ich auf eine „Circular Name Reference“-Warnung.
Das ist der Kern des Problems:
function set_it {
typeset -n var="$1"
var="hello:$var"
}
function call_it {
typeset -n var="$1"
set_it var
}
something="boff"
call_it something
echo "$something"
Ausführen:
$ ksh script.sh
hello:boff
$ bash script.sh
script.sh: line 4: warning: var: circular name reference
hello:
KornShell93 macht genau das, was ich will, aber Bash schlägt fehl und warnt auch vor der gleichen Sache in Zeile 2, wenn something
Variable im Skript heißt var
stattdessen.
Ich hätte gerne die var
Variable lokal für jede Funktion sein, weshalb ich typeset
verwende , aber Bash scheint es nicht zu mögen, eine Nameref auf eine Variable mit demselben Namen wie die Nameref selbst zu „dereferenzieren“. Ich kann local -n
nicht verwenden oder declare -n
da es in ksh
einbrechen würde dem diese fehlen, und selbst wenn ich es getan hätte, löst es das Problem nicht.
Die einzige Lösung, die ich gefunden habe, besteht darin, in jeder Funktion eindeutige Variablennamen zu verwenden , was ziemlich albern erscheint, da sie lokal sind.
Das Bash-Handbuch sagt Folgendes über typeset
:
typeset
[…]
-n
Geben Sie jedem Namen den nameref
-Attribut, wodurch es zu einem Namensverweis
auf eine andere Variable wird. Diese andere Variable
wird durch den Wert von name
definiert . Alle Verweise und
Zuordnungen zu name
, mit Ausnahme der Änderung von -n
-Attribut selbst, werden an der Variablen ausgeführt, auf die durch den Wert des Namens verwiesen wird.
[…]
Bei Verwendung in einer Funktion declare
und typeset
machen Sie jeden Namen
lokal, wie bei local
Befehl, es sei denn, der -g
Option
geliefert. Wenn auf einen Variablennamen =value
folgt , wird der
Wert der Variable auf value
gesetzt .
Es ist offensichtlich, dass ich etwas an Bashs Namensreferenzen und funktionslokalen Variablen nicht verstehe.
Die Frage ist also:Übersehe ich in diesem Fall etwas über Bashs Umgang mit Namensreferenzvariablen, oder ist dies ein Fehler/Fehlfunktion in Bash?
Aktualisieren :Ich arbeite derzeit mit GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15)
sowie mit GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0)
. Die mit macOS gelieferte Bash ist zu alt, um überhaupt Namensreferenzen zu kennen.
Aktualisieren :Noch kürzer:
function bug {
typeset -n var="$1"
printf "%sn" "$var"
}
var="hello"
bug var
Ergibt bash: warning: var: circular name reference
. Die var
in der Funktion sollte einen anderen Geltungsbereich haben aus der var
im globalen Rahmen. Dies erlegt dem Anrufer eine unnötige Beschränkung auf. Die Einschränkung lautet:„Sie dürfen Ihre Variablen nicht beliebig benennen, da es in dieser Funktion zu einem Namenskonflikt mit einem (lokalen) Nameref kommen kann.“
Akzeptierte Antwort:
Chet Ramey (Bash-Betreuer) sagt
Anfang des Jahres
gab es eine ausführliche Diskussion über Namerefs auf Bug-Bash. Ich habe einen vernünftigen Vorschlag, wie man dieses Verhalten ändern kann,
und ich werde ihn mir ansehen, nachdem bash-4.4 veröffentlicht wurde.
In der Zwischenzeit greife ich darauf zurück, die Namen meiner lokalen Nameref-Variablen leicht zu verschleiern, damit sie weder innerhalb der Bibliothek noch (hoffentlich) mit globalen Shell-Variablennamen kollidieren.
In bash
5.0 wurde dies geringfügig behoben (aber nicht wirklich behoben). Das folgende ist das beobachtete Verhalten:
$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello
Das zeigt, dass es funktioniert, aber es gibt auch ein paar Warnungen.
Der entsprechende NEWS-Eintrag lautet
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.