我知道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
导出的值都将保持静态(其中每次使用仍然会给出一个新值)。RANDOM
RANDOM
$RANDOM
这是因为每次引用外壳变量 RANDOM
inbash
使 shell 访问其内部get_random()
函数来为变量赋予新的随机值,但 shell 不会更新环境变量 RANDOM
。这与其他动态bash
变量(例如LINENO
、SECONDS
等BASHPID
)的行为类似。
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
然后还有更标准的变量,例如OPTIND
and OPTERR
(由getopts
)、and PS2
, PS3
(辅助提示符),甚至还有另一个“神奇”变量:(SECONDS
显示自 shell 启动以来的时间(以秒为单位))
在 Bash 中,您可以通过 . 查看所有变量及其导出状态declare -p
。带 标记的-x
是导出的,不带标记的x
是不导出的。 (有些会有其他标志,例如i
整数或r
只读。)
在 Zsh 或 ksh93 中,您可以使用,但 Zsh 通过在输出中更改为 来typeset -p
标记导出的变量,而不是使用标志。本身也会显示所有导出的变量,但这与运行 得到的结果大致相同。typeset
export
export
env
答案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
...
该变量没有作为引用传递。