Não encontrei nada sobre isso em todas as minhas pesquisas.
No código abaixo, Bar1
age como eu esperaria que uma variável "normal" agisse (já que help declare
diz que -g
só é "vista" em chamadas de função): ela muda de valor dependendo do escopo (externo ou interno).
Bar2
, sendo declarado "simplesmente", também age como eu esperava (estando gfhjnfd
no escopo externo e blat
no escopo interno.
Mas Foo
é uma variável globalmente imutável. help declare
diz apenas "para tornar NAMEs somente leitura". Onde esse recurso estendido (e indesejado) está documentado?
$ cat test.sh
#!/bin/bash
declare -r Foo=bar
declare -g Bar1=fdhtbn
declare Bar2=gfhjnfd
X()
{
local Foo=$1
local Bar1=snorkel
local Bar2=$2
echo Foo in X = $Foo
echo Bar1 in X = $Bar1
echo Bar2 in X = $Bar2
}
echo Foo, above X, = $Foo
echo Bar1, above X = $Bar1
echo Bar2, above X = $Bar2
echo
X baz blat
echo
echo Foo, below X, = $Foo
echo Bar1, below X = $Bar1
echo Bar2, below X = $Bar2
$ ./test.sh
Foo, above X, = bar
Bar1, above X = fdhtbn
Bar2, above X = gfhjnfd
./test.sh: line 9: local: Foo: readonly variable
Foo in X = bar
Bar1 in X = snorkel
Bar2 in X = blat
Foo, below X, = bar
Bar1, below X = fdhtbn
Bar2, below X = gfhjnfd
Se
readonly
em um escopo impedirá que uma variável com o mesmo nome seja declarada em escopos filhos (nos shells que possuem escopo dinâmico, como bash) varia entre os shells¹.Isso surgiu durante as discussões do grupo de Austin sobre a especificação
local
do escopo para variáveis no POSIXsh
(um esforço agora abandonado porque a obtenção de um consenso (sobre muitos outros aspectos) se mostrou impossível).No bash, isso é intencional e o mantenedor disse que não mudaria isso (pelo menos não no ambiente padrão), pois é considerado uma medida de segurança.
readonly
pode ser usado para duas finalidades não totalmente compatíveis:const
de C, embora aqui isso aconteça em tempo de execução).$PATH
,$HISTFILE
(embora um administrador que queira fornecer um ambiente de shell restrito provavelmente deseje definir mais variáveis somente leitura, comoLD_PRELOAD
,PERL5LIB
...) precisaria permanecer somente leitura para evitar que os usuários contornassem as restrições.No bash, as modificações de
$PATH
(que possui os únicos comandos permitidos) em shells restritos dependem doreadonly
atributo, por isso é importante que essas variáveis não possam ser modificadas (incluindo sua lista de atributos ou escopos) mesmo em escopos filhos.No zsh,
$PATH
e algumas outras variáveis (incluindoLD_PRELOAD
, mas nãoPERL5LIB
,PYTHONPATH
...) são restritas , mas não por meio do atributo somente leitura, portanto,readonly
podem ser usadas de forma confiável para o primeiro uso mencionado acima, mas isso significa que se o seu restrito- ambiente tem alguns comandos escritos emperl
oupython
, os usuários podem ignorar as restrições por meio das variáveisPERL5LIB
/PYTHONPATH
ambiente, por exemplo, e torná-los somente leitura não ajudará, pois os usuários podem fazertypeset +r PERL5LIB
para remover esse atributo somente leitura ou sombreá-lo em um escopo filho com um não -somente leitura um.¹ Consulte Lista de shells que suportam a palavra-chave `local` para definir variáveis locais para obter mais detalhes sobre o escopo local em vários shells do tipo POSIX.
O problema subjacente aqui é que a
local
palavra-chave não cria realmente uma variável local, ou pelo menos não no sentido que você espera.De acordo com o Manual de Referência do Bash :
e
(onde negrito representa minha ênfase).
Em termos de ciência da computação, o Bash usa escopo dinâmico em vez de escopo léxico ; mas do ponto de vista de um programador típico que vive no ano de 2024, o que isto realmente significa é que
local
não cria uma variável local, apenas modifica temporariamente a variável global. Sua mágica especial é restaurar automaticamente o valor original da variável (e outras propriedades) quando a função retorna, o que é útil, mas não é uma implementação completa de "variáveis locais" no sentido que você espera.Então, se
local
pudesse substituirreadonly
, algo assim:imprimiria
4
em vez de3
- a variávelthree
não seria realmente somente leitura.Como Stéphane Chazelas aponta em sua resposta, alguns shells permitem override . Mas eu diria que isso é um erro em qualquer shell que tenha o mesmo comportamento básico do Bash (ou seja, modificar temporariamente uma variável global em vez de criar uma variável local separada), e esse comportamento realmente entra em conflito com a intenção de . Só posso supor que a motivação deles era fazer com que as variáveis fossem um pouco mais parecidas com variáveis locais verdadeiras, mas isso não ajuda, desde que não sejam verdadeiramente locais.
local
readonly
local
readonly
local
Isto está documentado
local
emwww.gnu.org/software/bash/manual/bash.html#Bash-Builtins
Acho isso surpreendente, pois a primeira frase diz:
Isso implica que uma nova variável é criada com escopo restrito a essa função. Há um argumento de que uma constante global deve ser preservada de forma confiável.