Por que não consigo definir uma variável somente leitura chamada path no zsh?

Por que não consigo definir uma variável somente leitura chamada path no zsh?

Em zsh, pathé uma variável de array especial, cujo conteúdo está vinculado à variável conhecida PATH.

Tão especial, na verdade, que definir e chamar a função

f() { local -r path=42 }

causa o erro f: read-only variable: path. Se a variável local for declarada como mutável (ou seja, sem -r), tudo funcionará conforme o esperado. Não consegui reproduzir esse erro com outros nomes de variáveis.

Por que esse erro ocorre e é intencional? Existem regras semelhantes para outros nomes?

Estou usando o zsh 5.2 (x86_64-apple-darwin16.0) no macOS 10.12.6.

Responder1

DR não reutiliza "parâmetros integrados especiais", como pathporque eles são especiais. Ou de acordo comA lista de discussãopode-se usar a -hbandeira:

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

(No entanto, mudar pathpara um número inteiro pode atrapalhar o código subsequente que esquece essa substituição e assume pathque é path...)

Segue-se uma pesquisa mais longa (mas perdi totalmente a -hcoisa de esconder ...)

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

Esta é uma propriedade (recurso? bug?) de variáveis ​​especiais, mas não de variáveis ​​similares vinculadas pelo usuário:

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

Existem vários outros parâmetros que exibem esse comportamento:

% 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

Então algumas variáveis ​​são como emFazenda de animaismais especial que outros. Esta mensagem de erro vem de vários lugares onde Src/params.cse modifica para imprimir qual mensagem é a mensagem específica que encontramos ao compilar zsh:

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

É o 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;
    }

Isto mostra que o problema acontece em outro lugar; variáveis ​​não especiais, sem dúvida, não foram PM_READONLYdefinidas, enquanto as variáveis ​​especiais que falharam, sim. O próximo lugar óbvio para procurar é o código localque tem vários nomes ( typeset export…). Todos eles são integrados, então podem ser encontrados escondidos nas profundezas doSrc/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),

Todas elas chamam bin_typesetcom vários sinalizadores definidos, então vamos estudar a fonte dessa função... xingando nos comentários, confira. Observa que as coisas estão complicadas, confira. Nada realmente salta à vista, embora a toca do coelho (para quando a -mopção "tratar argumentos como padrões" fornãoset, que é o caso aqui) parece levar à typeset_singlefunção...

Há algum código POSIXBUILTINSrelacionado a readonly, mas está desativado em meus shells de teste

% print $options[POSIXBUILTINS]
off

então vou ignorar esse código (espero. Poderia ser um covil shoggoth e não uma mera toca de coelho?). Enquanto isso! Alguns pontos de depuração para o PM_READONLYsinalizador sendo ativado pathpela linha a seguir

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

Que por sua vez vem da onvariável que por sua vez já está ligada quando a typeset_singlefunção é inserida, suspiro, então vamos lá bin_typeset... ok, basicamente tem um TYPESET_OPTSTRque de alguma forma através de algumas macros habilita PM_READONLYpor padrão; quando, em vez disso, uma variável fornecida pelo usuário passa por esse caminho de código, ela PM_READONLYé desativada e tudo fica bem.

Se isso pode ser alterado para que variáveis ​​especiais como pathpossam ser feitas somente leitura é uma questão para um desenvolvedor ZSH (tente a lista de discussão zsh-workers?), caso contrário, enquanto isso, não mexa com as variáveis ​​especiais.

informação relacionada