Warum kann ich in zsh keine schreibgeschützte Variable mit dem Namen „Pfad“ definieren?

Warum kann ich in zsh keine schreibgeschützte Variable mit dem Namen „Pfad“ definieren?

In zsh pathist eine spezielle Array-Variable, deren Inhalt mit der bekannten PATHVariable 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 pathsie speziell sind. Oder gemäßDie Mailinglisteman kann die -hFlagge verwenden:

% () { local -hr path=42; echo $path }
42
% 

(Die Änderung in eine Ganzzahl kann jedoch pathzu Problemen mit dem nachfolgenden Code führen, da dieser diese Überschreibung vergisst und pathstattdessen davon ausgeht, dass path...)

Es folgt ein längeres Herumstöbern (aber die -hSache 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.cdenen, wenn sie geändert wird, um auszudrucken, welche Meldung die spezifische Meldung ist, die wir beim Kompilieren zshfinden:

% () { 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_READONLYgesetzt, während spezielle Variablen, die fehlschlagen, gesetzt sind. Der nächste offensichtliche Ort, an dem man nachsehen sollte, ist der Code, localder 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_typesetmit 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 -mOption „Argumente als Muster behandeln“nichtgesetzt ist, was hier der Fall ist) scheint zu der typeset_singleFunktion zu führen ...

Es gibt Code für POSIXBUILTINS, readonlyder 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_READONLYaktiviert 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 onVariable, die bereits aktiviert ist, wenn die typeset_singleFunktion aufgerufen wird, seufz, also zurück zum bin_typesetAusgangspunkt ... okay, im Grunde gibt es ein , TYPESET_OPTSTRdas irgendwie über einige Makros PM_READONLYstandardmäßig aktiviert wird; wenn stattdessen eine vom Benutzer bereitgestellte Variable durch diesen Codepfad läuft, PM_READONLYwird das deaktiviert und alles ist gut.

Ob dies geändert werden kann, sodass spezielle Variablen wie pathschreibgeschü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.

verwandte Informationen