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.