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 path
porque eles são especiais. Ou de acordo comA lista de discussãopode-se usar a -h
bandeira:
% () { local -hr path=42; echo $path }
42
%
(No entanto, mudar path
para um número inteiro pode atrapalhar o código subsequente que esquece essa substituição e assume path
que é path
...)
Segue-se uma pesquisa mais longa (mas perdi totalmente a -h
coisa 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.c
se 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_READONLY
definidas, enquanto as variáveis especiais que falharam, sim. O próximo lugar óbvio para procurar é o código local
que 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_typeset
com 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 -m
opção "tratar argumentos como padrões" fornãoset, que é o caso aqui) parece levar à typeset_single
função...
Há algum código POSIXBUILTINS
relacionado 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_READONLY
sinalizador sendo ativado path
pela 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 on
variável que por sua vez já está ligada quando a typeset_single
função é inserida, suspiro, então vamos lá bin_typeset
... ok, basicamente tem um TYPESET_OPTSTR
que de alguma forma através de algumas macros habilita PM_READONLY
por 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 path
possam 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.