mcmxciv Asked: 2018-07-06 00:22:35 +0800 CST2018-07-06 00:22:35 +0800 CST 2018-07-06 00:22:35 +0800 CST 为什么 $RANDOM 不包含在“env”的输出中? 772 我知道env是一个shell命令,它可以用来打印当前环境变量的列表。而且据我了解,RANDOM也是一个环境变量。 那么,为什么当我env在 Linux 上启动时,输出不包括RANDOM? environment-variables shell 4 个回答 Voted Best Answer Kusalananda 2018-07-06T00:24:50+08:002018-07-06T00:24:50+08:00 RANDOM不是环境变量。它是一些 shell 维护的 shell 变量。一般默认不导出。这就是为什么它没有出现在env. 一旦它至少被使用过一次,它就会出现在 的输出中set,它本身会列出当前 shell 会话中的 shell 变量(和函数)及其值。此行为取决于 shell 并pdksh在 OpenBSD上使用,即使以前未使用过RANDOM也会列出。set 这个答案的其余部分涉及如果RANDOM被导出(即变成环境变量)会发生什么。 导出它export RANDOM会使它成为一个环境变量,但它的使用将受到严重限制,因为它在子进程中的值将是“随机但静态”(意味着它将是一个不变的随机数)。壳之间的确切行为不同。 在下面的示例中,我在 OpenBSD 上使用pdksh,并且在每次运行中都会得到一个新的随机值awk(但在同一实例中每次都是相同的值awk)。使用,我将在 的所有调用中bash获得完全相同的随机值。awk $ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }' 25444 25444 $ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }' 30906 30906 在中,无论在 shell 中如何使用bash,导出的值都RANDOM将保持静态RANDOM(每次使用$RANDOM仍然会给出一个新值)。 这是因为每次对shell 变量 RANDOM的引用bash都会使 shell 访问其内部get_random()函数以给变量一个新的随机值,但 shell 不会更新环境变量 RANDOM。这在行为上与其他动态bash变量类似,例如LINENO,SECONDS等BASHPID。 要更新 中的环境变量RANDOM,bash您必须为其分配 shell 变量的值RANDOM 并重新导出它: export RANDOM="$RANDOM" 我不清楚这是否会产生重新植入随机数生成器的额外副作用bash(但有根据的猜测是它不会)。 terdon 2018-07-06T00:44:40+08:002018-07-06T00:44:40+08:00 并非所有在 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 ilkkachu 2018-07-06T01:09:28+08:002018-07-06T01:09:28+08:00 大多数 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 然后还有更多的标准变量,例如OPTINDand OPTERR(由 使用getopts),and PS2, PS3(辅助提示),甚至还有另一个“神奇”变量:(SECONDS以秒为单位显示 shell 启动后的时间) 在 Bash 中,您可以使用 . 查看所有变量及其导出状态declare -p。有标记的-x是导出的,没有x的则不是。(有些会有其他标志i,如整数或r只读。) 在 Zsh 或 ksh93 中,您可以使用typeset -p,尽管 Zsh 通过在输出中更改typeset为来标记导出的变量export,而不是使用标志。export本身也会显示所有导出的变量,但这与运行env. slm 2018-07-06T00:44:39+08:002018-07-06T00:44:39+08:00 如果您为此进行谷歌搜索,则文档说明如下: $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 ... 该变量没有作为参考传递。 参考 $RANDOM:生成随机整数
RANDOM
不是环境变量。它是一些 shell 维护的 shell 变量。一般默认不导出。这就是为什么它没有出现在env
.一旦它至少被使用过一次,它就会出现在 的输出中
set
,它本身会列出当前 shell 会话中的 shell 变量(和函数)及其值。此行为取决于 shell 并pdksh
在 OpenBSD上使用,即使以前未使用过RANDOM
也会列出。set
这个答案的其余部分涉及如果
RANDOM
被导出(即变成环境变量)会发生什么。导出它
export RANDOM
会使它成为一个环境变量,但它的使用将受到严重限制,因为它在子进程中的值将是“随机但静态”(意味着它将是一个不变的随机数)。壳之间的确切行为不同。在下面的示例中,我在 OpenBSD 上使用
pdksh
,并且在每次运行中都会得到一个新的随机值awk
(但在同一实例中每次都是相同的值awk
)。使用,我将在 的所有调用中bash
获得完全相同的随机值。awk
在中,无论在 shell 中如何使用
bash
,导出的值都RANDOM
将保持静态RANDOM
(每次使用$RANDOM
仍然会给出一个新值)。这是因为每次对shell 变量
RANDOM
的引用bash
都会使 shell 访问其内部get_random()
函数以给变量一个新的随机值,但 shell 不会更新环境变量RANDOM
。这在行为上与其他动态bash
变量类似,例如LINENO
,SECONDS
等BASHPID
。要更新 中的环境变量
RANDOM
,bash
您必须为其分配 shell 变量的值RANDOM
并重新导出它:我不清楚这是否会产生重新植入随机数生成器的额外副作用
bash
(但有根据的猜测是它不会)。并非所有在 shell 会话中设置的变量都是环境变量。“环境变量”仅指那些已使用
export
内置函数导出到环境的变量。该env
命令仅打印此类环境变量。例如:如果要查看会话中设置的所有变量,无论它们是否已导出,都可以使用
set
:set
内置函数还返回函数,因此要仅查看变量,您可以使用:最后,该
RANDOM
变量的特殊之处在于它仅在您引用它时才被分配一个值。这在bash(1)中提到:因此,即使它是您认为的环境变量,也不会显示在其中,
env
因为直到您第一次调用它时才会设置它。这也是为什么它没有显示在set
:大多数 shell 将设置或使用 shell 设置或使用的许多其他变量,这些变量默认情况下不会导出到子进程。
在 Bash 中,有一些明显是特定于 Bash 的:
然后还有更多的标准变量,例如
OPTIND
andOPTERR
(由 使用getopts
),andPS2
,PS3
(辅助提示),甚至还有另一个“神奇”变量:(SECONDS
以秒为单位显示 shell 启动后的时间)在 Bash 中,您可以使用 . 查看所有变量及其导出状态
declare -p
。有标记的-x
是导出的,没有x
的则不是。(有些会有其他标志i
,如整数或r
只读。)在 Zsh 或 ksh93 中,您可以使用
typeset -p
,尽管 Zsh 通过在输出中更改typeset
为来标记导出的变量export
,而不是使用标志。export
本身也会显示所有导出的变量,但这与运行env
.如果您为此进行谷歌搜索,则文档说明如下:
如果您使用
strace
,您会看到$RANDOM
“变量”直接传递给命令,就好像它是任何普通的 shell 变量或环境变量一样,但它只是一个内置在 shell 中的内部函数,Bash,它正在执行扩展。与这个常规变量相比:
该变量没有作为参考传递。
参考