Why isn't $RANDOM included in the output of 'env'?

RANDOM is not an environment variable. It's a shell variable maintained by some shells. It is generally not exported by default. This is why it doesn't show up in the output of env.

Once it's been used at least once, it would show up in the output of set, which, by itself, lists the shell variables (and functions) and their values in the current shell session. This behaviour is dependent on the shell and using pdksh on OpenBSD, RANDOM would be listed by set even if not previously used.


The rest of this answer concerns what could be expected to happen if RANDOM was exported (i.e. turned into an environment variable).

Exporting it with export RANDOM would make it an environment variable but its use would be severely limited as its value in a child process would be "random but static" (meaning it would be an unchanging random number). The exact behaviour differs between shells.

I'm using pdksh on OpenBSD in the example below and I get a new random value in each awk run (but the same value every time within the same awk instance). Using bash, I would get exactly the same random value in all invocations of awk.

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

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

In bash, the exported value of RANDOM would remain static regardless of the use of RANDOM in the shell (where each use of $RANDOM would still give a new value).

This is because each reference to the shell variable RANDOM in bash makes the shell access its internal get_random() function to give the variable a new random value, but the shell does not update the environment variable RANDOM. This is similar in behaviour as with other dynamic bash variables, such as LINENO, SECONDS, BASHPID etc.

To update the environment variable RANDOM in bash, you would have to assign it the value of the shell variable RANDOM and re-export it:

export RANDOM="$RANDOM"

It is unclear to me if this would have the additional side effect of re-seeding the random number generator in bash or not (but an educated guess would be that it doesn't).


Not all variables that are set in your shell session are environment variables. "Environment variables" refers only to those variables that have been exported to the environment using the export builtin. The env command only prints such environment variables. For example:

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

If you want to see all variables set in your session, irrespective of whether they have been exported, you can use set:

$ set | grep foo=
foo=bar

The set builtin also returns functions, so to see variables only, you can use:

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

Finally, the RANDOM variable is special in that it is only assigned a value when you reference it. This is mentioned in 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.

So even if it were an environment variable as you thought, it wouldn't have been shown in env since it wouldn't be set until the first time you called it. That is also why it isn't shown 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

Most shells will have a number of other variables set or used by the shell that aren't exported to child processes by default.

In Bash, there are some obviously Bash-specific ones:

$ 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

Then there's more standard ones like OPTIND and OPTERR (used by getopts), and PS2, PS3 (the secondary prompts) and even another "magic" variable: SECONDS (shows the time in seconds since the shell started)

In Bash, you can see all the variables and their export status with declare -p. The ones marked with -x are exported, the ones without x aren't. (Some will have other flags like i for integer or r for read-only.)

In Zsh or ksh93, you can use typeset -p, though Zsh marks the exported variables by changing typeset to export in the output, instead of using flags. export by itself would also show all the exported variables, but that's about the same result you get by running env.