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

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

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

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

答案1

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

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


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

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

pdksh在下面的示例中,我在 OpenBSD 上使用,每次awk运行时我都会得到一个新的随机值(但是相同的每次在同一awk实例中的值)。使用bash,我会得到完全相同的随机值全部的调用awk

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

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

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

这是因为每次引用外壳变量 RANDOMinbash使 shell 访问其内部get_random()函数来为变量赋予新的随机值,但 shell 不会更新环境变量 RANDOM。这与其他动态bash变量(例如LINENOSECONDSBASHPID)的行为类似。

RANDOM要更新中的环境变量bash,您必须为其分配 shell 变量的值RANDOM 重新导出它:

export RANDOM="$RANDOM"

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

答案2

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

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

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

$ set | grep foo=
foo=bar

内置set函数还返回函数,因此要仅查看变量,您可以使用:

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

最后,该RANDOM变量很特殊,因为它仅在引用时才被赋值。这在重击(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

答案3

大多数 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

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

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

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

答案4

如果你用谷歌搜索这个,文档说明如下:

$RANDOM是一个内部 Bash功能(不是常量)返回伪随机数[1]0 - 32767 范围内的整数。它不应用于生成加密密钥。

如果您使用,strace您可以看到$RANDOM“变量”直接传递到命令,就像它是任何普通的 shell 变量或环境变量一样,但它只是内置于 shell 中的内部函数,Bash 正在执行扩展。

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

与此常规变量相比:

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

该变量没有作为引用传递。

参考

相关内容