Enquanto variáveis de ambiente podem ter qualquer nome (incluindo a string vazia) não contendo um sinal de igual ou um byte nulo, shells mapeiam variáveis de ambiente para variáveis shell e na maioria das shells, nomes de variáveis são limitados a caracteres alfanuméricos ASCII e _
onde o primeiro caractere não pode ser um dígito (exceto os parâmetros posicionais e outros especiais como $*
, $-
, $@
,…, (que não são mapeados para as variáveis de ambiente correspondentes)). Observe também que algumas variáveis são reserved / special por / para o shell.
Exceções a isso:
-
O shell rc
e seus derivados, como es
e akanga
, suportam qualquer nome, exceto a sequência vazia, e aqueles que são todos numéricos ou contêm =
caracteres (e sempre exportam todas as variáveis para o ambiente e tenha cuidado com variáveis especiais como *
, status
, pid
...):
; '%$£"' = test
; echo $'%$£"'
test
; '' = x
zero-length variable name
;
No entanto, ele usa sua própria codificação para variáveis cujo nome não contém alnums ou para arrays quando passado no ambiente dos comandos que estão sendo executados:
$ rc -c '+ = zzz; __ = zzz; a = (zzz xxx); env' | sed -n /zzz/l
__2b=zzz$
__5f_=zzz$
a=zzz$ Stéphane=1
$ echo "$Stéphane"
1
1xxx$
$ env +=x rc -c "echo $'+'"
x
$ env __2b=x rc -c "echo $'+'"
x
-
AT & T ksh
, yash
e zsh
(também bash
, mas apenas para caracteres de byte único) suportam alnums na localidade atual, não apenas na ASCII.
$ env %%%=test 1=%%% a.b=%%% mksh -c env | grep %%%
$ env %%%=test 1=%%% a.b=%%% bash -c env | grep %%%
%%%=test
a.b=%%%
1=%%%
$ perl -le '$ENV{""}="%%%"; exec "bash", "-c", "env"' | grep %%%
$ perl -le '$ENV{""}="%%%"; exec "zsh", "-c", "env"' | grep %%%
=%%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
execve("/bin/ash",a,e);}'|tcc -run - | grep %%%
$ echo 'main(){char*a[]={"sh","-c","env",0};char*e[]={"%%%",0};
execve("/bin/zsh",a,e);}'|tcc -run - | grep %%%
%%%
Nesses shells, você pode alterar o local para considerar a maioria dos caracteres como alfa, mas ainda assim isso não funcionaria para caracteres ASCII como .
. Você pode enganar zsh
ou ksh
pensando que £
é uma letra, mas não que .
ou qualquer outro caractere ASCII (onde é permitido caracteres em nomes de variáveis, não para [[:alpha:]]
glob, por exemplo) .
-
ksh93
tem variáveis especiais cujo nome contém um ponto como ${.sh.version}
, mas elas não são mapeadas para variáveis de ambiente e são especiais. O .
é para garantir que não conflite com outras variáveis. Se ele tivesse escolhido chamá-lo de $sh_version
, ele poderia ter scripts potencialmente quebrados que já usavam essa variável (veja, por exemplo, como zsh
tem problemas com suas variáveis de matriz / hash especiais $path
ou $commands
csh) que quebra alguns scripts.
Note que, além dos shells que não suportam essas variáveis, alguns shells como pdksh / mksh fazem removê-los do ambiente que recebem ( bash
remove aquele com um nome vazio, ash
, ksh
e bash
remove as cadeias de ambiente que não contêm um caractere =
):
#! /bin/ksh -
perl -e 'exit 1 unless defined($ENV{"a.b"})' || exec env a.b=%%% "$0" "$@"
Para resumir, o melhor é ficar com nomes de variáveis suportados pela maioria dos shells e até tentar usar letras maiúsculas para variáveis de ambiente (e minúsculas ou maiúsculas e minúsculas para variáveis de shell não exportadas) evitando aquelas que são especiais em shells ( como
IFS
,
PS1
,
BASH_VERSION
...).
Se você precisar definir uma variável como essa em um shell que não a suporte, mas não a descartará, poderá recorrer novamente, com algo como:
gdb --batch-silent -ex 'call putenv("a.b=%%%")' --pid="$$"
(obviamente, se você precisar fazer isso no meio do script, isso não vai ajudar, mas você pode dar uma olhada em essa abordagem para salvar e restaurar o ambiente de execução do shell em uma nova execução).
Ou tente a abordagem do depurador:
; '%$£"' = test
; echo $'%$£"'
test
; '' = x
zero-length variable name
;
(esse parece funcionar com zsh
, yash
, csh
e tcsh
no Linux amd64, mas não com nenhum dos outros shells que eu tentei ( mksh
, ksh93
, bash
, dash
)).