为什么 $RANDOM 不包含在“env”的输出中?

mcm*_*civ 23 shell environment-variables

我知道env是一个shell命令,它可以用来打印当前环境变量的列表。而且据我了解,RANDOM也是一个环境变量。

那么为什么当我env在 Linux 上启动时,输出不包括RANDOM

Kus*_*nda 42

RANDOM不是环境变量。它是由一些 shell 维护的 shell 变量。默认情况下一般不导出。这就是为什么它没有出现在env.

一旦它至少被使用过一次,它就会出现在 的输出中set,它本身就列出了当前 shell 会话中的 shell 变量(和函数)及其值。此行为取决于 shell 并pdksh在 OpenBSD上使用RANDOMset即使以前未使用,也会列出。


这个答案的其余部分涉及如果RANDOM导出(即变成环境变量)可能会发生什么。

导出它export RANDOM会使它成为环境变量,但它的使用将受到严重限制,因为它在子进程中的值将是“随机但静态的”(意味着它将是一个不变的随机数)。壳之间的确切行为不同。

我在pdksh下面的示例中在 OpenBSD 上使用,并且在每次awk运行中获得一个新的随机值(但在同一实例中每次都具有相同的awk)。使用bash,我将在所有 的调用中获得完全相同的随机值awk

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

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906
Run Code Online (Sandbox Code Playgroud)

在 中bashRANDOM无论RANDOM在 shell 中如何使用, 的导出值都将保持静态(每次使用 时$RANDOM仍会给出一个新值)。

这是因为每个参考shell变量 RANDOMbash使shell访问其内部get_random()功能来给变量赋新的随机值,但外壳不更新环境变量 RANDOM。这是因为与其他动态行为类似的bash变量,例如LINENOSECONDSBASHPID等。

要更新环境变量RANDOMbash,你将不得不为它分配shell变量的值,RANDOM 重新将其导出:

export RANDOM="$RANDOM"
Run Code Online (Sandbox Code Playgroud)

我不清楚这是否会产生重新播种随机数生成器的额外副作用bash(但有根据的猜测是不会)。

  • @l0b0 从某种意义上说,它是随机的,您将无法预测它。显然,一旦你读过它,它就不再是随机的,因为它不会改变(除非像我展示的那样重新导出,在这种情况下,环境变量将获得一个新的随机值)。这就是为什么我说它是随机但静态的。我现在已经在文本中稍微澄清了这一点。 (3认同)

ter*_*don 16

并非在 shell 会话中设置的所有变量都是环境变量。“环境变量”仅指使用export内置函数导出到环境中的那些变量。该env命令仅打印此类环境变量。例如:

$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar
Run Code Online (Sandbox Code Playgroud)

如果要查看会话中设置的所有变量,无论它们是否已导出,都可以使用set

$ set | grep foo=
foo=bar
Run Code Online (Sandbox Code Playgroud)

set内建也返回功能,所以只看到变量,您可以使用:

set | grep  '^[^[:space:]]*='
Run Code Online (Sandbox Code Playgroud)

最后,该RANDOM变量的特殊之处在于它仅在您引用它时才被赋予一个值。这在bash(1) 中提到:

RANDOM

    每次引用此参数时,都会生成 0 到 32767 之间的随机整数。随机数序列可以通过为 分配一个值来初始化RANDOM。如果RANDOM未设置,它将失去其特殊属性,即使随后被重置。

因此,即使它是您认为的环境变量,它也不会显示出来,env因为直到您第一次调用它时才会设置它。这也是为什么它没有显示在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
Run Code Online (Sandbox Code Playgroud)


ilk*_*chu 5

大多数 shell 都会设置或使用许多其他变量,这些变量默认情况下不会导出到子进程。

在 Bash 中,有一些明显是 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
Run Code Online (Sandbox Code Playgroud)

然后还有更标准的变量,例如OPTINDand OPTERR(由getopts)、and PS2, PS3(辅助提示符),甚至还有另一个“神奇”变量:(SECONDS显示自 shell 启动以来的时间(以秒为单位))

在 Bash 中,您可以通过 . 查看所有变量及其导出状态declare -p。带 标记的-x是导出的,不带标记的x是不导出的。(有些会有其他标志,例如i整数或r只读。)

在 Zsh 或 ksh93 中,您可以使用,但 Zsh 通过在输出中更改为 来typeset -p标记导出的变量,而不是使用标志。本身也会显示所有导出的变量,但这与运行 得到的结果大致相同。typesetexportexportenv