Por que $ RANDOM não está incluído na saída de 'env'?

22

Eu sei que env é um comando shell, pode ser usado para imprimir uma lista das variáveis de ambiente atuais. E, tanto quanto eu entendo, RANDOM também é uma variável de ambiente.

Então, por que, quando eu abro env no Linux, a saída não inclui RANDOM ?

    
por mcmxciv 05.07.2018 / 10:22

4 respostas

42

RANDOM não é uma variável de ambiente. É uma variável de shell mantida por alguns shells. Geralmente não é exportado por padrão. É por isso que ele não aparece na saída de env .

Uma vez que tenha sido usado pelo menos uma vez, apareceria na saída de set , que, por si só, lista as variáveis (e funções) do shell e seus valores no shell atual sessão. Este comportamento é dependente do shell e usando pdksh no OpenBSD, RANDOM seria listado por set mesmo se não usado anteriormente.

O restante dessa resposta diz respeito ao que poderia acontecer se RANDOM fosse exportado (ou seja, transformado em uma variável de ambiente).

Exportá-lo com export RANDOM tornaria uma variável de ambiente, mas seu uso seria seriamente limitado, pois seu valor em um processo filho seria "aleatório, mas estático" (significando que seria um número aleatório imutável). O comportamento exato difere entre os shells.

Estou usando pdksh no OpenBSD no exemplo abaixo e recebo um novo valor aleatório em cada awk run (mas o mesmo valor toda vez dentro da mesma awk instance ). Usando bash , eu obteria exatamente o mesmo valor aleatório em todas invocações de awk .

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
25444 25444

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906

Em bash , o valor exportado de RANDOM permaneceria estático, independentemente do uso de RANDOM no shell (em que cada uso de $RANDOM ainda forneceria um novo valor).

Isso ocorre porque cada referência à variável shell RANDOM in bash faz o shell acessar sua função get_random() interna para dar à variável um novo valor aleatório, mas o shell não atualize a variável de ambiente RANDOM . Isso é semelhante no comportamento de outras variáveis bash dinâmicas, como LINENO , SECONDS , BASHPID etc.

Para atualizar a variável de ambiente RANDOM in bash , você deve atribuir a ela o valor da variável de shell RANDOM e reexportá-la:

export RANDOM="$RANDOM"

Não está claro para mim se isso teria o efeito colateral adicional de semear o gerador de números aleatórios em bash ou não (mas um palpite seria que isso não acontece).

    
por 05.07.2018 / 10:24
16

Nem todas as variáveis configuradas na sua sessão do shell são variáveis de ambiente. "Variáveis de ambiente" refere-se apenas àquelas variáveis que foram exportadas para o ambiente usando o export builtin. O comando env apenas imprime essas variáveis ambiente . Por exemplo:

$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar

Se você quiser ver todas as variáveis definidas em sua sessão, independentemente de terem sido exportadas, você pode usar set :

$ set | grep foo=
foo=bar

O set builtin também retorna funções, portanto, para ver apenas as variáveis, você pode usar:

set | grep  '^[^[:space:]]*='

Por fim, a variável RANDOM é especial, pois só recebe um valor quando você faz referência a ela. Isso é mencionado em bash (1) :

RANDOM

    Each time this parameter is referenced, a random integer between 0 and 32767 is generated.  The sequence of random numbers may be initialized by assigning a value to RANDOM.  If RANDOM is unset, it loses its special properties, even if it is subsequently reset.

Assim, mesmo que fosse uma variável de ambiente, como você pensava, ela não teria sido mostrada em env , já que não seria definida até a primeira vez que você a chamou. É também por isso que não é mostrado em set :

$ set | grep RAN   ## returns nothing, RANDOM is unset
$ echo "$RANDOM"   ## this will assign a value to RANDOM
1234
$ set | grep RAN   ## so now it will also appear in the output of set 
RANDOM=1234
    
por 05.07.2018 / 10:44
4

A maioria dos shells terá um número de outras variáveis definidas ou usadas pelo shell que não são exportadas para processos filho por padrão.

No Bash, há alguns obviamente específicos do Bash:

$ echo "${!BASH*}"
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION
$ echo $BASH_VERSION
4.4.12(1)-release
$ env|grep -c BASH
0

Depois, há outros mais comuns, como OPTIND e OPTERR (usados por getopts ), e PS2 , PS3 (os prompts secundários) e até outra variável "mágica": SECONDS (mostra o tempo em segundos desde o início do shell)

No Bash, você pode ver todas as variáveis e seu status de exportação com declare -p . Os marcados com -x são exportados, aqueles sem x não são. (Alguns terão outros sinalizadores como i para inteiro ou r para somente leitura.)

Em Zsh ou ksh93, você pode usar typeset -p , embora Zsh marque as variáveis exportadas alterando typeset para export na saída, em vez de usar sinalizadores. export por si só também mostra todas as variáveis exportadas, mas esse é o mesmo resultado que você obtém executando env .

    
por 05.07.2018 / 11:09
2

Se você pesquisar no Google, os documentos indicarão o seguinte:

$RANDOM is an internal Bash function (not a constant) that returns a pseudorandom [1] integer in the range 0 - 32767. It should not be used to generate an encryption key.

Se você usa strace , pode ver que a variável $RANDOM "é passada diretamente para comandos como se fosse uma variável de shell comum ou uma variável de ambiente, mas é apenas uma função interna que é incorporada ao shell Bash, está fazendo a expansão.

$ strace -t echo "random value: $RANDOM"
04:37:58 execve("/bin/echo", ["echo", "random value: 30795"], [/* 27 vars */]) = 0
04:37:58 brk(NULL)                      = 0x19c1000
04:37:58 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9841351000
...

vs. esta variável regular:

$ strace -t echo "random value: $SOMEVAR"
04:40:19 execve("/bin/echo", ["echo", "random value: helloworld"], [/* 27 vars */]) = 0
04:40:19 brk(NULL)                      = 0x154b000
04:40:19 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f659d2eb000
...

A variável não está sendo passada como referência.

Referências

por 05.07.2018 / 10:44