Perché $ RANDOM non è incluso nell'output di 'env'?


23

So che envè un comando shell, può essere utilizzato per stampare un elenco delle variabili di ambiente correnti. E per quanto ho capito, RANDOMè anche una variabile d'ambiente.

Quindi perché, quando avvio envsu Linux, l'output non include RANDOM?


4
envnon è un comando shell poiché di solito non è incorporato nella shell.
schily,

@schily BTW per Bash, declare -xè l'equivalente in una shell incorporata.
wjandrea,

Risposte:


42

RANDOMnon è una variabile d'ambiente. È una variabile di shell gestita da alcune shell. In genere non viene esportato per impostazione predefinita. Questo è il motivo per cui non viene visualizzato nell'output di env.

Una volta usato almeno una volta, verrebbe visualizzato nell'output di set, che, da solo, elenca le variabili (e le funzioni) della shell e i loro valori nella sessione della shell corrente. Questo comportamento dipende dalla shell e l'utilizzo pdkshsu OpenBSD, RANDOMsarebbe elencato setanche se non utilizzato in precedenza.


Il resto di questa risposta riguarda ciò che ci si potrebbe aspettare se RANDOMfosse esportato (cioè trasformato in una variabile d'ambiente).

Esportarlo con export RANDOMlo renderebbe una variabile d'ambiente ma il suo uso sarebbe fortemente limitato in quanto il suo valore in un processo figlio sarebbe "casuale ma statico" (nel senso che sarebbe un numero casuale immutabile). Il comportamento esatto differisce tra le shell.

Sto usando pdkshOpenBSD nell'esempio seguente e ottengo un nuovo valore casuale in ogni awkcorsa (ma lo stesso valore ogni volta nella stessa awkistanza). Usando bash, otterrei esattamente lo stesso valore casuale in tutte le invocazioni di awk.

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

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

In bash, il valore esportato di RANDOMrimarrebbe statico indipendentemente dall'uso RANDOMnella shell (dove ogni uso di $RANDOMdarebbe comunque un nuovo valore).

Questo perché ogni riferimento alla variabile shell RANDOM in bashfa sì che la shell acceda alla sua get_random()funzione interna per dare alla variabile un nuovo valore casuale, ma la shell non aggiorna la variabile d'ambiente RANDOM . Questo è un comportamento simile come con altri dinamiche bashvariabili, come LINENO, SECONDS, BASHPIDetc.

Per aggiornare la variabile d'ambiente RANDOMin bash, si dovrà assegnare il valore della variabile di shell RANDOM e riesportazione esso:

export RANDOM="$RANDOM"

Non mi è chiaro se questo avrebbe l'effetto collaterale aggiuntivo di ripetere il seeding del generatore di numeri casuali basho meno (ma un'ipotesi istruita sarebbe che non lo faccia).


1
Fa RANDOManche avere un valore prima di utilizzarlo? Ho sempre pensato che fosse popolato solo quando chiamato.
terdon

1
Non lo è, il manuale di Bash lo menziona.
terdon

1
Anche se lo fai anche export RANDOMo declare -p RANDOM, sembra, quindi non sono sicuro che sia utile che non esista prima di essere referenziato ...
ilkkachu,

1
"Il suo valore in un processo figlio sarebbe casuale, ma statico." Se è statico, non è casuale , sia che si tratti di tre byte o sedici.
l0b0,

3
@ l0b0 Sarebbe casuale nel senso che non saresti in grado di prevederlo. Ovviamente, una volta letto, non è più casuale poiché non cambierà (a meno che non venga riesportato come ho mostrato, nel qual caso la variabile d'ambiente otterrebbe un nuovo valore casuale). Questo è il motivo per cui ho detto che è casuale ma statico. L'ho chiarito un po 'nel testo ora.
Kusalananda

16

Non tutte le variabili impostate nella sessione della shell sono variabili di ambiente. "Variabili d'ambiente" si riferisce solo a quelle variabili che sono state esportate nell'ambiente usando l' exportintegrato. Il envcomando stampa solo tali variabili d' ambiente . Per esempio:

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

Se vuoi vedere tutte le variabili impostate nella tua sessione, indipendentemente dal fatto che siano state esportate, puoi usare set:

$ set | grep foo=
foo=bar

Il setbuiltin restituisce anche funzioni, quindi per vedere solo le variabili, puoi usare:

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

Infine, la RANDOMvariabile è speciale in quanto viene assegnato un valore solo quando lo si fa riferimento. Questo è menzionato in bash (1) :

RANDOM

    Ogni volta che si fa riferimento a questo parametro, viene generato un numero intero casuale compreso tra 0 e 32767. La sequenza di numeri casuali può essere inizializzata assegnando un valore a RANDOM. Se RANDOMnon è impostato, perde le sue proprietà speciali, anche se viene successivamente ripristinato.

Quindi, anche se fosse una variabile d'ambiente come pensavi, non sarebbe stata mostrata in envquanto non sarebbe stata impostata fino alla prima volta che l'hai chiamata. Questo è anche il motivo per cui non è mostrato in 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

Questa è una scoperta interessante, per quanto riguarda set | grep RAN. Non me lo sarei aspettato. FWIW, credo che non possa essere previsto dalla documentazione.
G-Man dice 'Reinstate Monica' il

1
PS Congratulazioni per aver raggiunto 120.000. (Immagino di averti appena messo sopra.)
G-Man dice 'Reinstate Monica' il

4

La maggior parte delle shell avrà un numero di altre variabili impostate o utilizzate dalla shell che non vengono esportate in processi figlio per impostazione predefinita.

In Bash, ce ne sono alcuni ovviamente specifici per 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

Poi ce ne sono di più standard come OPTINDe OPTERR(usato da getopts), e PS2, PS3(le istruzioni secondarie) e persino un'altra variabile "magica": SECONDS(mostra il tempo in secondi dall'inizio della shell)

In Bash puoi vedere tutte le variabili e il loro stato di esportazione con declare -p. Quelli contrassegnati con -xvengono esportati, quelli senza lo xsono. (Alcuni avranno altri flag come iper intero o rper sola lettura.)

In Zsh o ksh93, è possibile utilizzare typeset -p, anche se segna Zsh le variabili esportate modificando typesetal exportnell'output, invece di utilizzare bandiere. exportda solo mostrerebbe anche tutte le variabili esportate, ma si tratta dello stesso risultato che si ottiene eseguendo env.


2

Se vai su Google per questo, i documenti indicano quanto segue:

$RANDOMè una funzione Bash interna (non una costante) che restituisce un numero intero pseudocasuale [1] nell'intervallo 0 - 32767. Non deve essere utilizzato per generare una chiave di crittografia.

Se lo usi stracepuoi vedere che la $RANDOM"variabile" viene passata direttamente ai comandi come se fosse una normale variabile shell o una variabile d'ambiente, ma è solo una funzione interna che è integrata nella shell, Bash, che sta facendo l'espansione.

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

rispetto a questa variabile regolare:

$ 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 variabile non viene passata come riferimento.

Riferimenti


1
bene, non sta passando il valore espanso di $RANDOMo $SOMEVARattraverso un argomento della riga di comando e non come una variabile di ambiente? Avresti bisogno di exportentrambi per passarli attraverso l'ambiente.
ilkkachu,

No, questo non farebbe differenza. La shell li espande indipendentemente. Il modo in cui l'ho mostrato sta sostanzialmente mettendo in evidenza il fatto che la shell sta facendo l'espansione.
slm

2
L' straceoutput non sembra catturare la funzione interna gestita dalla shell. In entrambi i casi, la variabile è già stata espansa nella prima riga di strace. Non capisco quale differenza stai indicando. Cosa mi sto perdendo?
terdon

Mostrando che l' $RANDOMespansione avviene internamente alla shell. Fondamentalmente è la conferma che la shell sta determinando il valore e non sta passando un riferimento a una variabile. La shell quando sta espandendo la riga di comando per eseguire analisi $RANDOMe passa il modulo espanso a echo.
slm

2
Quindi, niente come una variabile d' ambiente , quindi.
Toby Speight,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.