Por que não consigo definir uma variável readon chamada caminho em zsh?

5

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

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. Eu 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.

    
por Halle Knast 26.11.2017 / 16:27

1 resposta

5

TL; DR não reutiliza "parâmetros internos especiais", como path , porque eles são especiais. Ou, de acordo com a Lista de Discussão , é possível usar o sinalizador -h :

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

(No entanto, alterar path para um número inteiro pode atrapalhar o código subseqüente que esquece essa substituição e assume path em vez de path ...)

Uma escavação mais longa segue (mas eu perdi totalmente a coisa -h hide ...)

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

Esta é uma propriedade (característica? erro?) de variáveis especiais, mas não variáveis semelhantes ligadas 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 em Animal Farm mais especiais do que outras. Esta mensagem de erro vem de vários lugares em Src/params.c , o que, se for modificado para imprimir qual mensagem é a mensagem específica que compilamos, que zsh find:

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

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

Isso mostra que o problema acontece em outro lugar; variáveis não especiais, sem dúvida, não têm PM_READONLY set enquanto as variáveis especiais que falham fazem. O próximo lugar óbvio a procurar é o código para local , que é usado por vários nomes ( typeset export ...). Estes são todos builtins assim podem ser encontrados à espreita nas profundezas de 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),

Estes todos chamam bin_typeset com vários flags set então vamos estudar a fonte para essa função ... jurando os comentários, confira. Anota que as coisas são complicadas, verifique. Nada realmente salta, embora o buraco do coelho (para quando o "tratar argumentos como padrões" -m opção é não definido, que é o caso aqui) parece levar à função typeset_single . ..

Existe algum código para POSIXBUILTINS relacionado a readonly , mas isso está desativado nas minhas shells de teste

% print $options[POSIXBUILTINS]
off

então eu vou ignorar esse código (espero. Poderia ser um covil shoggoth e não um simples buraco de coelho?). Enquanto isso! Alguns pontos de depuração para o sinalizador PM_READONLY estão sendo alternados para path pela seguinte linha

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

Qual, por sua vez, vem da variável on que por sua vez já está ativa quando a função typeset_single é inserida, suspiro, então voltando para bin_typeset vamos ... ok, basicamente existe um TYPESET_OPTSTR de alguma forma, através de algumas macros, permite PM_READONLY por padrão; quando, em vez disso, uma variável fornecida pelo usuário executar esse caminho de código, o PM_READONLY será desativado e tudo estará bem.

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

    
por 26.11.2017 / 23:57