¿Por qué no se incluye $ RANDOM en la salida de 'env'?

23

Sé que enves un comando de shell, se puede usar para imprimir una lista de las variables de entorno actuales. Y hasta donde yo entiendo, RANDOMtambién es una variable de entorno.

Entonces, ¿por qué, cuando inicio enven Linux, la salida no incluye RANDOM?

mcmxciv
fuente
44
envno es un comando de shell ya que generalmente no está integrado en el shell.
schily
@schily BTW para Bash, declare -xes el equivalente en un shell incorporado.
wjandrea

Respuestas:

42

RANDOMNo es una variable de entorno. Es una variable de shell mantenida por algunos shells. Generalmente no se exporta por defecto. Es por eso que no aparece en la salida de env.

Una vez que se ha utilizado al menos una vez, sería aparecer en la salida de set, que, por sí mismo, las listas de las variables de shell (y funciones) y sus valores en la sesión shell actual. Este comportamiento depende del shell y el uso pdkshen OpenBSD RANDOMse enumeraría setincluso si no se usaba anteriormente.


El resto de esta respuesta se refiere a lo que podría esperarse que suceda si RANDOMse exporta (es decir, se convierte en una variable de entorno).

Exportarlo lo export RANDOMconvertiría en una variable de entorno, pero su uso estaría muy limitado ya que su valor en un proceso secundario sería "aleatorio pero estático" (lo que significa que sería un número aleatorio inmutable). El comportamiento exacto difiere entre los depósitos.

Estoy usando pdkshOpenBSD en el ejemplo a continuación y obtengo un nuevo valor aleatorio en cada awkejecución (pero el mismo valor cada vez dentro de la misma awkinstancia). Utilizando bash, obtendría exactamente el mismo valor aleatorio en todas las invocaciones de awk.

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

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

En bash, el valor exportado de RANDOMpermanecería estático independientemente del uso de RANDOMen el shell (donde cada uso de $RANDOMtodavía daría un nuevo valor).

Esto se debe a que cada referencia a la variable de shell RANDOM en bashhace que el shell acceda a su get_random()función interna para darle a la variable un nuevo valor aleatorio, pero el shell no actualiza la variable de entorno RANDOM . Esto es similar en comportamiento como con otras dinámicas bashvariables, tales como LINENO, SECONDS, BASHPIDetc.

Para actualizar la variable de entorno RANDOMen bash, habría que asignarle el valor de la variable de shell RANDOM y reexportación que:

export RANDOM="$RANDOM"

Para mí no está claro si esto tendría el efecto secundario adicional de volver a sembrar el generador de números aleatorios basho no (pero una suposición educada sería que no lo hace).

Kusalananda
fuente
1
¿ RANDOMIncluso tiene un valor antes de usarlo? Siempre supuse que solo estaba poblado cuando se lo llamaba.
terdon
1
No lo es, el manual de bash lo menciona.
terdon
1
Aunque si lo hace, incluso export RANDOM, o declare -p RANDOM, lo que parece, así que no estoy seguro de si se trata de cualquier uso que no existe antes de que se hace referencia ...
ilkkachu
1
"Su valor en un proceso secundario sería aleatorio, pero estático". Si es estático, no es aleatorio , ya sean tres bytes o dieciséis.
l0b0
3
@ l0b0 Sería aleatorio en el sentido de que no sería capaz de predecirlo. Obviamente, una vez que lo haya leído, ya no es aleatorio, ya que no cambiará (a menos que vuelva a exportar como lo mostré, en cuyo caso la variable de entorno obtendría un nuevo valor aleatorio). Por eso dije que es aleatorio pero estático. He aclarado esto en el texto un poco ahora.
Kusalananda
16

No todas las variables que se configuran en su sesión de shell son variables de entorno. "Variables de entorno" se refiere solo a aquellas variables que se han exportado al entorno utilizando la función exportintegrada. El envcomando solo imprime tales variables de entorno . Por ejemplo:

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

Si desea ver todas las variables establecidas en su sesión, independientemente de si se han exportado, puede usar set:

$ set | grep foo=
foo=bar

El setbuiltin también devuelve funciones, por lo que para ver solo las variables, puede usar:

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

Finalmente, la RANDOMvariable es especial porque solo se le asigna un valor cuando se hace referencia a ella. Esto se menciona en bash (1) :

RANDOM

    Cada vez que se hace referencia a este parámetro, se genera un número entero aleatorio entre 0 y 32767. La secuencia de números aleatorios se puede inicializar asignando un valor a RANDOM. Si no RANDOMestá configurado, pierde sus propiedades especiales, incluso si posteriormente se restablece.

Entonces, incluso si fuera una variable de entorno como pensaba, no se habría mostrado envya que no se configuraría hasta la primera vez que la llamó. Por eso también no se muestra en 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
terdon
fuente
Ese es un descubrimiento interesante, con respecto set | grep RAN. No lo hubiera esperado. FWIW, creo que la documentación no puede predecirlo.
G-Man dice 'reinstalar a Monica' el
1
PD Felicitaciones por llegar a 120,000. (Supongo que solo te puse encima.)
G-Man dice 'Reinstate Monica' el
4

La mayoría de los shells tendrán una serie de otras variables establecidas o utilizadas por el shell que no se exportan a los procesos secundarios de forma predeterminada.

En Bash, hay algunos obviamente específicos de 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

Entonces hay otros más convencionales como OPTINDy OPTERR(usado por getopts), y PS2, PS3(las indicaciones secundarias) e incluso otra variable "mágica":SECONDS (muestra el tiempo en segundos desde el inicio de la concha)

En Bash, puede ver todas las variables y su estado de exportación con declare -p. Los marcados con -xse exportan, los que no lo xestán. (Algunos tendrán otras banderas como ipara entero or para solo lectura).

En Zsh o ksh93, puede usar typeset -p, aunque Zsh marca las variables exportadas cambiando typeseta exporten la salida, en lugar de usar banderas. exportpor sí solo también mostraría todas las variables exportadas, pero ese es el mismo resultado que obtienes al ejecutar env.

ilkkachu
fuente
2

Si buscas esto en Google, los documentos indican lo siguiente:

$RANDOMes una función Bash interna (no una constante) que devuelve un entero pseudoaleatorio [1] en el rango de 0 a 32767. No debe usarse para generar una clave de cifrado.

Si lo usa strace, puede ver que la $RANDOM"variable" se pasa directamente a los comandos como si fuera una variable de shell ordinaria o una variable de entorno, pero es solo una función interna que está integrada en el shell, Bash, que está haciendo la expansión.

$ 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 variable 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
...

La variable no se pasa como referencia.

Referencias

slm
fuente
1
bueno, ¿no es eso pasar el valor expandido de $RANDOMo a $SOMEVARtravés de un argumento de línea de comando, y no como una variable de entorno? Necesitarías exportambos para pasarlos por el entorno.
ilkkachu
No, eso no haría ninguna diferencia. El caparazón los expande independientemente. La forma en que lo mostré es básicamente resaltar el hecho de que el shell está haciendo la expansión.
slm
2
La stracesalida no parece captar la función interna ejecutada por el shell. En ambos casos, la variable ya se ha expandido en la primera línea de strace. No entiendo a qué diferencia estás apuntando. ¿Qué me estoy perdiendo?
terdon
Mostrando que la $RANDOMexpansión se realiza internamente al shell. Básicamente es la confirmación de que el shell está determinando el valor y no pasando una referencia a una variable. El shell cuando expande la línea de comando para ejecutar análisis $RANDOMy pasa el formulario expandido a echo.
slm
2
Entonces, nada como una variable de entorno , entonces.
Toby Speight