¿Por qué no puedo definir una variable de solo lectura denominada ruta en zsh?

¿Por qué no puedo definir una variable de solo lectura denominada ruta en zsh?

En zsh, pathes una variable de matriz especial, cuyo contenido está vinculado a la variable conocida PATH.

De hecho, es tan especial que definir y llamar a la función

f() { local -r path=42 }

causa el error f: read-only variable: path. Si la variable local se declara como mutable (es decir, sin -r), todo funciona como se esperaba. No he podido reproducir este error con otros nombres de variables.

¿Por qué ocurre este error y es intencional? ¿Existen reglas similares para otros nombres?

Estoy usando zsh 5.2 (x86_64-apple-darwin16.0) en macOS 10.12.6.

Respuesta1

TL;DR no reutilice "parámetros incorporados especiales", como pathporque son especiales. O segúnLa lista de correose puede usar la -hbandera:

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

(Sin embargo, cambiar patha un número entero podría estropear el código posterior que olvida esta anulación y asume que pathen su lugar es path...)

Sigue una investigación más larga (pero me perdí por completo el -hasunto de esconderse...)

% print ${(t)path}
array-special

Esta es una propiedad (¿característica? ¿Error?) de variables especiales, pero no de variables similares vinculadas por el usuario:

% () { 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

Hay varios otros parámetros que exhiben este comportamiento:

% 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

Entonces algunas variables son como enGranja de animalesmás especial que otros. Este mensaje de error proviene de varios lugares en Src/params.clos que, si se modifica para imprimir, cuál es el mensaje específico que encontramos al compilar zsh:

% () { local -r path }
% () { local -r path=foo }
(anon): read-only variable (setarrvalue): path

¿Es el código bastante genérico?

/**/
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;
    }

Esto demuestra que el problema ocurre en otra parte; Las variables no especiales sin duda no se han PM_READONLYestablecido, mientras que las variables especiales que fallan sí lo hacen. El siguiente lugar obvio para buscar es el código localque tiene varios nombres ( typeset export...). Todos estos son elementos incorporados, por lo que se pueden encontrar acechando en las profundidades deSrc/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),

Todos estos llaman bin_typesetcon varios indicadores configurados, así que estudiemos la fuente de esa función... juramento en los comentarios, verifique. Observa que la cosa está complicada, comprueba. En realidad, nada salta a la vista, aunque la madriguera del conejo (para cuando la -mopción "tratar los argumentos como patrones" está activada ).noset, que es el caso aquí) parece conducir a la typeset_singlefunción...

Hay algo de código POSIXBUILTINSrelacionado con readonly, pero está desactivado en mis shells de prueba.

% print $options[POSIXBUILTINS]
off

así que voy a ignorar ese código (espero. ¿Podría ser esto una guarida shoggoth y no una simple madriguera de conejo?). ¡Mientras tanto! Algunos puntos de depuración indican que la siguiente línea PM_READONLYactiva la banderapath

    /*
     * 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;

Lo cual a su vez proviene de la onvariable que a su vez ya está activada cuando typeset_singlese ingresa la función, suspiro, así que volvamos a bin_typeseteso... bueno, básicamente hay una TYPESET_OPTSTRque de alguna manera a través de algunas macros se habilita PM_READONLYde forma predeterminada; cuando, en cambio, una variable proporcionada por el usuario se ejecuta a través de esta ruta de código, PM_READONLYse desactiva y todo está bien.

Si esto se puede cambiar para que variables especiales como las que pathse pueden convertir en de solo lectura es una pregunta para un desarrollador de ZSH (¿pruebe la lista de correo de zsh-workers?); de lo contrario, mientras tanto, no pierda el tiempo con las variables especiales.

información relacionada