为什么'env'的输出中不包含$ RANDOM?


23

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

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


4
env不是shell命令,因为它通常不内置在shell中。
schily

Bash的@schily BTW与declare -x内置的shell等效。
wjandrea

Answers:


42

RANDOM不是环境变量。这是由一些shell维护的shell变量。默认情况下,通常不导出它。这就是为什么它不会出现在的输出中的原因env

一旦它已经至少使用过一次,它在输出显示出来set,这本身并列出了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

在中bashRANDOM无论RANDOMshell中使用的是什么,的导出值都将保持静态(其中每次使用$RANDOM仍将提供新值)。

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

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

export RANDOM="$RANDOM"

我不清楚这是否会对重新植入随机数生成器产生其他副作用bash(但有根据的猜测是,事实并非如此)。


1
难道RANDOM连一个值然后再使用它?我一直以为只在调用时填充它。
terdon

1
不是,bash手册中提到了它。
terdon

1
虽然,如果出现偶数export RANDOMdeclare -p RANDOM,它会出现,所以我不确定在引用之前它是否不存在它的任何用途……
ilkkachu

1
“它在子进程中的值是随机的,但是静态的。” 如果它是静态的,则它不是random,无论是三个字节还是十六个字节。
l0b0

3
@ l0b0就您将无法预测的意义而言,这是随机的。显然,一旦您阅读它,它就不再是随机的,因为它不会改变(除非重新导出,如我所示,在这种情况下,环境变量将获得一个新的随机值)。这就是为什么我说它是随机的但静态的。我现在已经在文字中对此进行了澄清。
库萨兰达

16

并非在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变量是特殊的,因为仅在引用变量时才为其赋值。这在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

关于,这是一个有趣的发现set | grep RAN。我不会期望的。FWIW,我相信文档无法预测。
G-Man说'Resstate Monica''July

1
PS恭喜您达到120,000。(我想我只是把你放过去了。)
G-Man说'Reinstate Monica'18'Jul

4

大多数Shell会设置一些其他变量,这些变量由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

然后还有更多的标准变量,例如OPTINDOPTERR(由所使用getopts),和PS2PS3(辅助提示),甚至还有另一个“魔术”变量:(SECONDS以秒为单位显示自启动外壳以来的时间)

在Bash中,您可以使用查看所有变量及其导出状态declare -p。标-x有的将被导出,没有标出的x将不被导出。(有些标志将带有其他标志,例如i整数或r只读标志。)

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


2

如果您用谷歌搜索,文档说明以下内容:

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

如果使用的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
...

该变量未作为参考传递。

参考文献


1
好吧,这不是通过命令行参数传递扩展值$RANDOM$SOMEVAR通过命令行参数传递,而不是作为环境变量传递吗?您需要export同时使它们通过环境。
ilkkachu

不,那不会有任何区别。不管如何,外壳都会扩展它们。我展示它的方式基本上是在强调外壳正在进行扩展的事实。
slm

2
strace输出似乎没有赶上通过shell中运行的内部功能。在这两种情况下,变量都已经在的第一行中进行了扩展strace。我不明白您要指的是什么。我想念什么?
terdon

表明$RANDOM扩展是在shell内部完成的。基本上可以确认shell正在确定值,而不是将引用传递给变量。外壳程序在扩展命令行以执行解析$RANDOM并将扩展形式传递给时echo
slm

2
因此,没有什么比环境变量好。
Toby Speight
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.