In zsh path
ist eine spezielle Array-Variable, deren Inhalt mit der bekannten PATH
Variable verknüpft ist.
So besonders, dass das Definieren und Aufrufen der Funktion
f() { local -r path=42 }
verursacht den Fehler f: read-only variable: path
. Wenn die lokale Variable als veränderlich deklariert ist (also ohne -r
), funktioniert alles wie erwartet. Ich konnte diesen Fehler mit anderen Variablennamen nicht reproduzieren.
Warum tritt dieser Fehler auf und ist er beabsichtigt? Gibt es ähnliche Regeln für andere Namen?
Ich verwende zsh 5.2 (x86_64-apple-darwin16.0) unter macOS 10.12.6.
Antwort1
TL;DR Verwenden Sie keine „speziellen integrierten Parameter“ wieder, da path
sie speziell sind. Oder gemäßDie Mailinglisteman kann die -h
Flagge verwenden:
% () { local -hr path=42; echo $path }
42
%
(Die Änderung in eine Ganzzahl kann jedoch path
zu Problemen mit dem nachfolgenden Code führen, da dieser diese Überschreibung vergisst und path
stattdessen davon ausgeht, dass path
...)
Es folgt ein längeres Herumstöbern (aber die -h
Sache mit dem Verstecken habe ich völlig übersehen...)
% print ${(t)path}
array-special
Dies ist eine Eigenschaft (Funktion? Fehler?) spezieller Variablen, jedoch nicht ähnlicher, vom Benutzer verknüpfter Variablen:
% () { typeset -r PATH=/blah; echo $PATH }
(anon): read-only variable: PATH
% typeset -Tar FOO=bar foo
% print $foo
bar
% print ${(t)foo}
array-readonly-tag_local
% () { local -r foo=blah; echo $foo }
blah
Es gibt verschiedene andere Parameter, die dieses Verhalten aufweisen:
% for p in $parameters[(I)*]; do print $p $parameters[$p]; done | grep array-
cdpath array-special
...
% () { local -r cdpath=42 }
(anon): read-only variable: cdpath
Einige Variablen sind also wie inTierfarmspezieller als andere. Diese Fehlermeldung kommt von verschiedenen Stellen, an Src/params.c
denen, wenn sie geändert wird, um auszudrucken, welche Meldung die spezifische Meldung ist, die wir beim Kompilieren zsh
finden:
% () { local -r path }
% () { local -r path=foo }
(anon): read-only variable (setarrvalue): path
Ist der eher generische Code
/**/
mod_export void
setarrvalue(Value v, char **val)
{
if (unset(EXECOPT))
return;
if (v->pm->node.flags & PM_READONLY) {
zerr("read-only variable (setarrvalue): %s", v->pm->node.nam);
freearray(val);
return;
}
Dies zeigt, dass das Problem woanders auftritt; nicht-spezielle Variablen sind zweifellos nicht PM_READONLY
gesetzt, während spezielle Variablen, die fehlschlagen, gesetzt sind. Der nächste offensichtliche Ort, an dem man nachsehen sollte, ist der Code, local
der eine Vielzahl von Namen hat ( typeset
export
...). Dies sind alles eingebaute Variablen, die man in den Tiefen von finden kann.Src/builtin.c
% grep BUILTIN Src/builtin.c | grep local
BUILTIN("local", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%ahi:%lp:%rtux", NULL),
Diese rufen alle bin_typeset
mit verschiedenen gesetzten Flags auf, also lasst uns den Quellcode für diese Funktion studieren... Fluchen in den Kommentaren, check. Hinweise, dass die Dinge kompliziert sind, check. Nichts springt wirklich heraus, obwohl das Kaninchenloch (für wenn die -m
Option „Argumente als Muster behandeln“nichtgesetzt ist, was hier der Fall ist) scheint zu der typeset_single
Funktion zu führen ...
Es gibt Code für POSIXBUILTINS
, readonly
der in meinen Test-Shells jedoch deaktiviert ist.
% print $options[POSIXBUILTINS]
off
also werde ich diesen Code ignorieren (hoffe ich. Könnte das eine Shoggoth-Höhle und kein bloßes Kaninchenloch sein?). In der Zwischenzeit! Einige Debugging-Hinweise darauf, dass das Flag durch die folgende Zeile PM_READONLY
aktiviert wirdpath
/*
* The remaining on/off flags should be harmless to use,
* because we've checked for unpleasant surprises above.
*/
pm->node.flags = (PM_TYPE(pm->node.flags) | on | PM_SPECIAL) & ~off;
Das wiederum kommt von der on
Variable, die bereits aktiviert ist, wenn die typeset_single
Funktion aufgerufen wird, seufz, also zurück zum bin_typeset
Ausgangspunkt ... okay, im Grunde gibt es ein , TYPESET_OPTSTR
das irgendwie über einige Makros PM_READONLY
standardmäßig aktiviert wird; wenn stattdessen eine vom Benutzer bereitgestellte Variable durch diesen Codepfad läuft, PM_READONLY
wird das deaktiviert und alles ist gut.
Ob dies geändert werden kann, sodass spezielle Variablen wie path
schreibgeschützt gemacht werden können, ist eine Frage für einen ZSH-Entwickler (versuchen Sie es mit der Mailingliste „zsh-workers“?), ansonsten spielen Sie in der Zwischenzeit nicht mit den speziellen Variablen herum.